trusted_cert_add.c [plain text]
#include "trusted_cert_add.h"
#include "trusted_cert_utils.h"
#include "security_tool.h"
#include "keychain_utilities.h"
#include <Security/Security.h>
#include <Security/SecTrust.h>
#include <Security/SecTrustSettings.h>
#include <Security/SecTrustSettingsPriv.h>
#include <Security/oidsalg.h>
#include <errno.h>
#include <unistd.h>
#include <utilities/fileIo.h>
#include <CoreFoundation/CoreFoundation.h>
static CFDataRef readFileData(
const char *fileName)
{
unsigned char *d;
size_t dLen;
if(readFileSizet(fileName, &d, &dLen)) {
return NULL;
}
CFDataRef cfd = CFDataCreate(NULL, (const UInt8 *)d, dLen);
free(d);
return cfd;
}
static int writeFileData(
const char *fileName,
CFDataRef cfd)
{
unsigned long l = (unsigned long)CFDataGetLength(cfd);
int rtn = writeFileSizet(fileName, CFDataGetBytePtr(cfd), l);
if(rtn) {
fprintf(stderr, "Error %d writing to %s\n", rtn, fileName);
}
else if(!do_quiet) {
fprintf(stdout, "...wrote %ld bytes to %s\n", l, fileName);
}
return rtn;
}
static int appendConstraintsToDict(
const char *appPath,
const char *policy,
const char *policyStr,
SecTrustSettingsResult resultType,
CSSM_RETURN allowErr,
SecTrustSettingsKeyUsage keyUse,
CFMutableDictionaryRef *dict)
{
if(*dict == NULL) {
*dict = CFDictionaryCreateMutable(NULL,
0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
const CSSM_OID *oid = NULL;
if(policy != NULL) {
oid = policyStringToOid(policy);
if(oid == NULL) {
return 2;
}
SecPolicyRef policyRef = oidToPolicy(oid);
if(policyRef == NULL) {
return 2;
}
CFDictionaryAddValue(*dict, kSecTrustSettingsPolicy, policyRef);
CFRelease(policyRef);
}
if(appPath != NULL) {
SecTrustedApplicationRef appRef;
OSStatus ortn = SecTrustedApplicationCreateFromPath(appPath, &appRef);
if(ortn) {
cssmPerror("SecTrustedApplicationCreateFromPath", ortn);
return -1;
}
CFDictionaryAddValue(*dict, kSecTrustSettingsApplication, appRef);
CFRelease(appRef);
}
if(policyStr != NULL) {
CFStringRef pstr = CFStringCreateWithCString(NULL, policyStr, kCFStringEncodingUTF8);
CFDictionaryAddValue(*dict, kSecTrustSettingsPolicyString, pstr);
CFRelease(pstr);
}
if(allowErr) {
SInt32 ae = (SInt32)allowErr;
CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &ae);
CFDictionaryAddValue(*dict, kSecTrustSettingsAllowedError, cfNum);
CFRelease(cfNum);
}
if(keyUse != 0) {
SInt32 ku = (SInt32)keyUse;
CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &ku);
CFDictionaryAddValue(*dict, kSecTrustSettingsKeyUsage, cfNum);
CFRelease(cfNum);
}
if(resultType != kSecTrustSettingsResultTrustRoot) {
SInt32 rt = (SInt32)resultType;
CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &rt);
CFDictionaryAddValue(*dict, kSecTrustSettingsResult, cfNum);
CFRelease(cfNum);
}
return 0;
}
int
trusted_cert_add(int argc, char * const *argv)
{
extern char *optarg;
extern int optind;
OSStatus ortn;
int arg;
SecTrustSettingsDomain domain = kSecTrustSettingsDomainUser;
int ourRtn = 0;
SecKeychainRef kcRef = NULL;
int defaultSetting = 0;
char *certFile = NULL;
SecCertificateRef certRef = NULL;
char *settingsFileIn = NULL;
char *settingsFileOut = NULL;
CFDataRef settingsIn = NULL;
CFDataRef settingsOut = NULL;
char *appPath = NULL;
SecTrustSettingsResult resultType = kSecTrustSettingsResultTrustRoot;
CSSM_RETURN allowErr = CSSM_OK;
SecTrustSettingsKeyUsage keyUse = 0;
CFMutableArrayRef trustSettings = NULL;
int haveConstraints = 0;
const int maxPolicies = 16; char *policyNames[maxPolicies];
char *policyStrings[maxPolicies];
int allowedErrors[maxPolicies];
int policyNameCount = 0, policyStringCount = 0, allowedErrorCount = 0;
if(argc < 2) {
return 2;
}
optind = 1;
while ((arg = getopt(argc, argv, "dr:a:p:s:e:u:k:i:o:Dh")) != -1) {
switch (arg) {
case 'd':
domain = kSecTrustSettingsDomainAdmin;
break;
case 'r':
if(!strcmp(optarg, "trustRoot")) {
resultType = kSecTrustSettingsResultTrustRoot;
}
else if(!strcmp(optarg, "trustAsRoot")) {
resultType = kSecTrustSettingsResultTrustAsRoot;
}
else if(!strcmp(optarg, "deny")) {
resultType = kSecTrustSettingsResultDeny;
}
else if(!strcmp(optarg, "unspecified")) {
resultType = kSecTrustSettingsResultUnspecified;
}
else {
return 2;
}
haveConstraints = 1;
break;
case 'p':
if (policyNameCount < maxPolicies) {
policyNames[policyNameCount++] = optarg;
} else {
fprintf(stderr, "Too many policy arguments.\n");
return 2;
}
haveConstraints = 1;
break;
case 'a':
appPath = optarg;
haveConstraints = 1;
break;
case 's':
if (policyStringCount < maxPolicies) {
policyStrings[policyStringCount++] = optarg;
} else {
fprintf(stderr, "Too many policy string arguments.\n");
return 2;
}
haveConstraints = 1;
break;
case 'e':
if (allowedErrorCount < maxPolicies) {
if (!strcmp("certExpired", optarg))
allowErr = -2147409654; else if (!strcmp("hostnameMismatch", optarg))
allowErr = -2147408896; else
allowErr = (CSSM_RETURN)atoi(optarg);
if (!allowErr) {
fprintf(stderr, "Invalid value for allowed error.\n");
return 2;
}
allowedErrors[allowedErrorCount++] = allowErr;
} else {
fprintf(stderr, "Too many \"allowed error\" arguments.\n");
return 2;
}
haveConstraints = 1;
break;
case 'u':
keyUse = (SecTrustSettingsKeyUsage)atoi(optarg);
haveConstraints = 1;
break;
case 'k':
kcRef = keychain_open(optarg);
if(kcRef == NULL) {
return 1;
}
break;
case 'i':
settingsFileIn = optarg;
break;
case 'o':
settingsFileOut = optarg;
break;
case 'D':
defaultSetting = 1;
break;
default:
case 'h':
return 2;
}
}
if(ourRtn) {
goto errOut;
}
switch(argc - optind) {
case 0:
break;
case 1:
certFile = argv[optind];
break;
default:
ourRtn = 2;
goto errOut;
}
if(defaultSetting && (certFile != NULL)) {
fprintf(stderr, "Can't specify cert when manipulating default setting.\n");
ourRtn = 2;
goto errOut;
}
if((certFile == NULL) && (settingsFileOut == NULL) && !defaultSetting) {
fprintf(stderr, "No cert file specified.\n");
ourRtn = 2;
goto errOut;
}
if((settingsFileOut != NULL) && (domain != kSecTrustSettingsDomainUser)) {
fprintf(stderr, "Can't specify both domain and a settingsFile\n");
ourRtn = 2;
goto errOut;
}
if((settingsFileIn != NULL) && (settingsFileOut == NULL)) {
fprintf(stderr, "Can't specify settingsFileIn and no settingsFileOut\n");
ourRtn = 2;
goto errOut;
}
if(haveConstraints) {
int i, j, k;
for (i=0; i<policyNameCount; i++) {
if (!trustSettings) {
trustSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
if (policyStringCount) {
for (j=0; j<policyStringCount; j++) {
if (allowedErrorCount) {
for (k=0; k<allowedErrorCount; k++) {
CFMutableDictionaryRef constraintDict = NULL;
ourRtn = appendConstraintsToDict(appPath,
policyNames[i],
policyStrings[j],
resultType,
allowedErrors[k],
keyUse,
&constraintDict);
if (!ourRtn) {
CFArrayAppendValue(trustSettings, constraintDict);
CFRelease(constraintDict); }
}
} else { CFMutableDictionaryRef constraintDict = NULL;
ourRtn = appendConstraintsToDict(appPath,
policyNames[i],
policyStrings[j],
resultType, 0, keyUse,
&constraintDict);
if (!ourRtn) {
CFArrayAppendValue(trustSettings, constraintDict);
CFRelease(constraintDict); }
}
}
} else { if (allowedErrorCount) {
for (k=0; k<allowedErrorCount; k++) {
CFMutableDictionaryRef constraintDict = NULL;
ourRtn = appendConstraintsToDict(appPath,
policyNames[i],
NULL,
resultType,
allowedErrors[k],
keyUse,
&constraintDict);
if (!ourRtn) {
CFArrayAppendValue(trustSettings, constraintDict);
CFRelease(constraintDict); }
}
} else { CFMutableDictionaryRef constraintDict = NULL;
ourRtn = appendConstraintsToDict(appPath,
policyNames[i],
NULL,
resultType, 0, keyUse,
&constraintDict);
if (!ourRtn) {
CFArrayAppendValue(trustSettings, constraintDict);
CFRelease(constraintDict); }
}
}
if(ourRtn) {
goto errOut;
}
}
}
if(haveConstraints && !trustSettings) {
CFMutableDictionaryRef constraintDict = NULL;
trustSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
ourRtn = appendConstraintsToDict(appPath, NULL, NULL,
resultType, allowErr, keyUse,
&constraintDict);
if (!ourRtn) {
CFArrayAppendValue(trustSettings, constraintDict);
CFRelease(constraintDict); } else {
goto errOut;
}
}
if(settingsFileIn) {
settingsIn = readFileData(settingsFileIn);
if(settingsIn == NULL) {
fprintf(stderr, "Error reading file %s\n", settingsFileIn);
ourRtn = 1;
goto errOut;
}
}
else if(settingsFileOut) {
ortn = SecTrustSettingsSetTrustSettingsExternal(NULL,
NULL, NULL, &settingsIn);
if(ortn) {
cssmPerror("SecTrustSettingsSetTrustSettings", ortn);
ourRtn = 1;
goto errOut;
}
}
if(defaultSetting) {
certRef = kSecTrustSettingsDefaultRootCertSetting;
}
else if(certFile != NULL) {
if(readCertFile(certFile, &certRef)) {
fprintf(stderr, "Error reading file %s\n", certFile);
ourRtn = 1;
goto errOut;
}
if(kcRef) {
ortn = SecCertificateAddToKeychain(certRef, kcRef);
switch(ortn) {
case noErr:
case errSecDuplicateItem:
break;
default:
cssmPerror("SecCertificateAddToKeychain", ortn);
ourRtn = 1;
goto errOut;
}
}
}
if(settingsFileOut) {
if(certRef != NULL) {
ortn = SecTrustSettingsSetTrustSettingsExternal(settingsIn,
certRef, trustSettings, &settingsOut);
if(ortn) {
cssmPerror("SecTrustSettingsSetTrustSettings", ortn);
ourRtn = 1;
goto errOut;
}
}
else {
settingsOut = settingsIn;
settingsIn = NULL;
}
ourRtn = writeFileData(settingsFileOut, settingsOut);
if(ourRtn) {
fprintf(stderr, "Error writing to %s\n", settingsFileOut);
goto errOut;
}
}
else {
if(certRef == NULL) {
fprintf(stderr, "Internal error in trusted_cert_add\n");
ourRtn = 1;
goto errOut;
}
ortn = SecTrustSettingsSetTrustSettings(certRef, domain, trustSettings);
if(ortn) {
cssmPerror("SecTrustSettingsSetTrustSettings", ortn);
ourRtn = 1;
}
}
errOut:
if((certRef != NULL) & (certRef != kSecTrustSettingsDefaultRootCertSetting)) {
CFRelease(certRef);
}
CFRELEASE(trustSettings);
CFRELEASE(kcRef);
CFRELEASE(settingsIn);
CFRELEASE(settingsOut);
return ourRtn;
}
int
trusted_cert_remove(int argc, char * const *argv)
{
OSStatus ortn = noErr;
int ourRtn = 0;
SecTrustSettingsDomain domain = kSecTrustSettingsDomainUser;
int defaultSetting = 0;
SecCertificateRef certRef = NULL;
char *certFile = NULL;
extern char *optarg;
extern int optind;
int arg;
optind = 1;
while ((arg = getopt(argc, argv, "dDh")) != -1) {
switch (arg) {
case 'd':
domain = kSecTrustSettingsDomainAdmin;
break;
case 'D':
defaultSetting = 1;
break;
default:
case 'h':
return 2;
}
}
switch(argc - optind) {
case 0:
break;
case 1:
certFile = argv[optind];
break;
default:
return 2;
}
if((certFile == NULL) && !defaultSetting) {
fprintf(stderr, "No cert file specified.\n");
return 2;
}
if((certFile != NULL) && defaultSetting) {
fprintf(stderr, "Can't specify cert when manipulating default setting.\n");
return 2;
}
if(defaultSetting) {
certRef = kSecTrustSettingsDefaultRootCertSetting;
}
else {
if(readCertFile(certFile, &certRef)) {
fprintf(stderr, "Error reading file %s\n", certFile);
return 1;
}
}
ortn = SecTrustSettingsRemoveTrustSettings(certRef, domain);
if(ortn) {
cssmPerror("SecTrustSettingsRemoveTrustSettings", ortn);
ourRtn = 1;
}
if((certRef != NULL) & (certRef != kSecTrustSettingsDefaultRootCertSetting)) {
CFRelease(certRef);
}
return ourRtn;
}