void sec_error_print(int errcode, char *prefix) { if (prefix == NULL) fprintf(stderr, "%s\n", sec_error(errcode)); else fprintf(stderr, "%s:%s\n", prefix, sec_error(errcode)); }
static int do_keychain_set_settings(const char *keychainName, SecKeychainSettings newKeychainSettings) { SecKeychainRef keychain = NULL; OSStatus result; if (keychainName) { keychain = keychain_open(keychainName); if (!keychain) { result = 1; goto cleanup; } } result = SecKeychainSetSettings(keychain, &newKeychainSettings); if (result) { sec_error("SecKeychainSetSettings %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result)); } cleanup: if (keychain) CFRelease(keychain); return result; }
void cmd_flash_nand(const char *arg, void *data, unsigned sz) { u8 msg[128] = {0}; if(sz == 0) { fastboot_okay(""); return; } //Please DO NOT get any data for reference if security check is not passed if(!security_check(&data, &sz, 0, arg)) { sprintf(msg, "\nSecurity deny - Err:0x%x \n", sec_error()); dprintf(DBG_LV, msg); fastboot_fail_wrapper(msg); return; } dprintf(DBG_LV, "cmd_flash_nand, data:0x%x\n",*(int*)data); if(cmd_flash_nand_img(arg,data,sz)) { //[Security] Notify security check that is the end. sz = 0; security_check(&data, &sz, IMAGE_TRUNK_SIZE, arg); } }
static int do_lock(const char *keychainName) { SecKeychainRef keychain = NULL; OSStatus result; if (keychainName) { keychain = keychain_open(keychainName); if (!keychain) { result = 1; goto loser; } } result = SecKeychainLock(keychain); if (result) { sec_error("SecKeychainLock %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result)); } loser: if (keychain) CFRelease(keychain); return result; }
OSStatus makeMasterPassword(const char *fvmkcName, const char *masterPasswordPassword, uint32 keySizeInBits, SecKeychainRef *keychainRef) { /* OSStatus SecFileVaultMakeMasterPassword(CFStringRef masterPasswordPassword); *** In the real code, this will be done directly rather than exec'ing a tool, since there are too many parameters to specify *** this needs to be done as root, since the keychain will be a system keychain /usr/bin/certtool y c k=/Library/Keychains/FileVaultMaster.keychain p=<masterPasswordPassword> /usr/bin/certtool c k=/Library/Keychains/FileVaultMaster.keychain o=/Library/Keychains/FileVaultMaster.cer Two steps: create the keychain, then create the keypair */ SecAccessRef initialAccess = NULL; if (!masterPasswordPassword) { sec_error("You must supply a non-empty password"); return -2; } // We return an error if the keychain already exists OSStatus status = SecKeychainCreate(fvmkcName, (UInt32) strlen(masterPasswordPassword), masterPasswordPassword, false, initialAccess, keychainRef); if (status!=noErr) { if (status==errSecDuplicateKeychain || status==CSSMERR_DL_DATASTORE_ALREADY_EXISTS) sec_error("The keychain file %s already exists", fvmkcName); return status; } // Create the key pair char host[PATH_MAX]; int rx = gethostname(host, sizeof(host)); if (rx) strcpy(host, "localhost"); CFStringRef hostName = CFSTR("FileVault Recovery Key"); // This is what shows up in Keychain Access display CFStringRef userName = CFStringCreateWithCString(kCFAllocatorDefault, host, kCFStringEncodingUTF8); CFDataRef certData = NULL; printf("Generating a %d bit key pair; this may take several minutes\n", keySizeInBits); status = createPair(hostName,userName,*keychainRef,keySizeInBits, &certData); if (status) sec_error("Error in createPair: %s", sec_errstr(status)); if (certData) CFRelease(certData); return status; }
/* * Generate a key pair using the CSPDL. */ OSStatus generateKeyPair( CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE dlDbHand, CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA uint32 keySizeInBits, const char *keyLabel, // C string CSSM_KEY_PTR *pubKeyPtr, // mallocd, created, RETURNED CSSM_KEY_PTR *privKeyPtr) // mallocd, created, RETURNED { CSSM_KEY_PTR pubKey = (CSSM_KEY_PTR)(APP_MALLOC(sizeof(CSSM_KEY))); CSSM_KEY_PTR privKey = (CSSM_KEY_PTR)(APP_MALLOC(sizeof(CSSM_KEY))); if((pubKey == NULL) || (privKey == NULL)) { return memFullErr; } CSSM_RETURN crtn; CSSM_KEYUSE pubKeyUse; CSSM_KEYUSE privKeyUse; pubKeyUse = CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP; privKeyUse = CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP; crtn = srCspGenKeyPair(cspHand, &dlDbHand, keyAlg, keyLabel, (int) strlen(keyLabel) + 1, keySizeInBits, pubKey, pubKeyUse, CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF, privKey, privKeyUse, CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE); if(crtn) { APP_FREE(pubKey); APP_FREE(privKey); return paramErr; } /* bind private key to cert by public key hash */ crtn = setPubKeyHash(cspHand, dlDbHand, pubKey, keyLabel); if(crtn) { sec_error("setPubKeyHash: Error setting public key hash. Continuing at peril: %s", sec_errstr(crtn)); } *pubKeyPtr = pubKey; *privKeyPtr = privKey; return noErr; }
int keychain_import(int argc, char * const *argv) { int ch; int verbose=0; const char *keybag=NULL; const char *password=NULL; while ((ch = getopt(argc, argv, "vk:p:")) != -1) { switch (ch) { case 'v': verbose++; break; case 'k': keybag=optarg; break; case 'p': password=optarg; break; default: return 2; /* Trigger usage message. */ } } argc -= optind; argv += optind; if(keybag==NULL) { sec_error("-k is required\n"); return 2; } if (argc != 1) { sec_error("<backup> is required\n"); return 2; /* Trigger usage message. */ } return do_keychain_import(argv[0], keybag, password); }
/* Convert a reference key to a raw key. */ static CSSM_RETURN refKeyToRaw( CSSM_CSP_HANDLE cspHand, const CSSM_KEY *refKey, CSSM_KEY_PTR rawKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(rawKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase NULL, // wrapping key NULL, // init vector CSSM_PADDING_NONE, // Padding 0, // Params &ccHand); if(crtn) { sec_error("CSSM_CSP_CreateSymmetricContext: refKeyToRaw context err: %s", sec_errstr(crtn)); return crtn; } crtn = CSSM_WrapKey(ccHand, &creds, refKey, NULL, // DescriptiveData rawKey); if(crtn != CSSM_OK) { sec_error("CSSM_WrapKey: refKeyToRaw wrap err: %s", sec_errstr(crtn)); return crtn; } CSSM_DeleteContext(ccHand); return CSSM_OK; }
/* Execute a single command. */ static int execute_command(int argc, char * const *argv) { const command *c; int found = 0; /* Nothing to do. */ if (argc == 0) return 0; for (c = commands; c->c_name; ++c) { if (match_command(c->c_name, argv[0])) { found = 1; break; } } if (found) { int result; /* Reset getopt for command proc. */ optind = 1; optreset = 1; if (do_verbose) { int ix; fprintf(stderr, "%s", c->c_name); for (ix = 1; ix < argc; ++ix) fprintf(stderr, " \"%s\"", argv[ix]); fprintf(stderr, "\n"); } result = c->c_func(argc, argv); if (result == 2) fprintf(stderr, "Usage: %s %s\n %s\n", c->c_name, c->c_usage, c->c_help); return result; } else { sec_error("unknown command \"%s\"", argv[0]); return 1; } }
static int do_keychain_show_info(const char *keychainName) { SecKeychainRef keychain = NULL; SecKeychainSettings keychainSettings = { SEC_KEYCHAIN_SETTINGS_VERS1 }; OSStatus result; if (keychainName) { keychain = keychain_open(keychainName); if (!keychain) { result = 1; goto loser; } } result = SecKeychainCopySettings(keychain, &keychainSettings); if (result) { sec_error("SecKeychainCopySettings %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result)); goto loser; } fprintf(stderr,"Keychain \"%s\"%s%s", keychainName ? keychainName : "<NULL>", keychainSettings.lockOnSleep ? " lock-on-sleep" : "", keychainSettings.useLockInterval ? " use-lock-interval" : ""); if (keychainSettings.lockInterval == INT_MAX) fprintf(stderr," no-timeout\n"); else fprintf(stderr," timeout=%ds\n", (int)keychainSettings.lockInterval); loser: if (keychain) CFRelease(keychain); return result; }
/* The help command. */ static int help(int argc, char * const *argv) { const command *c; if (argc > 1) { char * const *arg; for (arg = argv + 1; *arg; ++arg) { int found = 0; for (c = commands; c->c_name; ++c) { if (match_command(c->c_name, *arg)) { found = 1; break; } } if (found) printf("Usage: %s %s\n", c->c_name, c->c_usage); else { sec_error("%s: no such command: %s", argv[0], *arg); return 1; } } } else { for (c = commands; c->c_name; ++c) printf(" %-36s %s\n", c->c_name, c->c_help); } return 0; }
BOOL cmd_flash_nand_img(const char *arg, void *data, unsigned sz) { int index; u64 offset,size; int img_type; char *p_type; char msg[256]; index = partition_get_index(arg); if(index == -1){ fastboot_fail_wrapper("partition get index fail"); return FALSE; } if(!is_support_flash(index)){ sprintf(msg,"partition '%s' not support flash\n",arg); fastboot_fail_wrapper(msg); return FALSE; } offset = partition_get_offset(index); if(offset == (u64)(-1)){ fastboot_fail_wrapper("partition get offset fail"); return FALSE; }else{ printf("get offset: 0x%llx\n",offset); } size = partition_get_size(index); if(size == (u64)(-1)){ fastboot_fail_wrapper("partition get size fail"); return FALSE; }else{ printf("get size: 0x%llx\n",size); } if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) { if (memcmp((void *)data, BOOT_MAGIC, strlen(BOOT_MAGIC))) { fastboot_fail_wrapper("image is not a boot image"); return FALSE; } } { char i_type[20] = {0}; get_image_type(data,sz,(char *)i_type); partition_get_type(index,&p_type); if(strcmp(i_type,p_type)){ display_info("[warning]image type is not match with partition type\n"); dprintf(DBG_LV, "[warning]image type'%s' is not match with partition type'%s'",i_type,p_type); } if(!strcmp(i_type,"raw data")){ img_type = RAW_DATA_IMG; }else if(!strcmp(i_type,"yaffs2")){ img_type = YFFS2_IMG; }else if(!strcmp(i_type,"ubifs")){ img_type = UBIFS_IMG; }else{ dprintf(DBG_LV, "image type '%s' unkown\n",i_type); display_info("\nimage type unkown"); return FALSE; } } TIME_START; display_info("write flash ...."); printf("writing %d bytes to '%s' img_type %d\n", sz, arg,img_type); #if defined(MTK_MLC_NAND_SUPPORT) if (nand_write_img((u64)offset, (char*)data, sz,(u64)size,img_type)) { #else if (nand_write_img((u32)offset, (char*)data, sz,(u32)size,img_type)) { #endif fastboot_fail_wrapper("nand write image failure"); return FALSE; } printf("partition '%s' updated\n", arg); fastboot_ok_wrapper("write flash sucess",sz); return TRUE; } void cmd_flash_nand(const char *arg, void *data, unsigned sz) { char msg[128] = {0}; if(sz == 0) { fastboot_okay(""); return; } #ifdef MTK_SECURITY_SW_SUPPORT //Please DO NOT get any data for reference if security check is not passed if(!security_check((u8**)&data, &sz, 0, arg)) { sprintf(msg, "\nSecurity deny - Err:0x%x \n", sec_error()); dprintf(DBG_LV, msg); fastboot_fail_wrapper(msg); return; } #endif dprintf(DBG_LV, "cmd_flash_nand, data:0x%x\n",*(int*)data); if(cmd_flash_nand_img(arg,data,sz)) { //[Security] Notify security check that is the end. sz = 0; #ifdef MTK_SECURITY_SW_SUPPORT security_check((u8**)&data, &sz, IMAGE_TRUNK_SIZE, arg); #endif } }
void cmd_flash_emmc(const char *arg, void *data, unsigned sz) { sparse_header_t *sparse_header; /* 8 Byte Magic + 2048 Byte xml + Encrypted Data */ //unsigned int *magic_number = (unsigned int *) data; BOOL write_ret = TRUE; char msg[128] = {0}; #if 0 if (magic_number[0] == DECRYPT_MAGIC_0 && magic_number[1] == DECRYPT_MAGIC_1) { #ifdef SSD_ENABLE ret = decrypt_scm((u32 **) &data, &sz); #endif if (ret != 0) { dprintf(CRITICAL, "ERROR: Invalid secure image\n"); return; } } else if (magic_number[0] == ENCRYPT_MAGIC_0 && magic_number[1] == ENCRYPT_MAGIC_1) { #ifdef SSD_ENABLE ret = encrypt_scm((u32 **) &data, &sz); #endif if (ret != 0) { dprintf(CRITICAL, "ERROR: Encryption Failure\n"); return; } } #endif if(sz == 0) { fastboot_okay(""); return; } #ifdef MTK_SECURITY_SW_SUPPORT //[Security] Please DO NOT get any data for reference if security check is not passed if(!security_check((u8**)&data, &sz, 0, arg)) { sprintf(msg, "\nSecurity deny - Err:0x%x \n", sec_error()); dprintf(DBG_LV, msg); fastboot_fail_wrapper((char*)msg); return; } #endif sparse_header = (sparse_header_t *) data; dprintf(DBG_LV, "cmd_flash_emmc, data:0x%x,, n sparse_header->magic = 0x%x\n",*(int*)data, sparse_header->magic ); if (sparse_header->magic != SPARSE_HEADER_MAGIC) { write_ret = cmd_flash_emmc_img(arg, data, sz); } else { write_ret = cmd_flash_emmc_sparse_img(arg, data, sz); } if( write_ret ) { //[Security] Notify security check that is the end. sz = 0; #ifdef MTK_SECURITY_SW_SUPPORT security_check((u8**)&data, &sz, IMAGE_TRUNK_SIZE, arg); #endif } }
static int do_keychain_set_password(const char *keychainName, const char* oldPassword, const char* newPassword) { SecKeychainRef keychain = NULL; OSStatus result = 1; UInt32 oldLen = (oldPassword) ? strlen(oldPassword) : 0; UInt32 newLen = (newPassword) ? strlen(newPassword) : 0; char *oldPass = (oldPassword) ? (char*)oldPassword : NULL; char *newPass = (newPassword) ? (char*)newPassword : NULL; char *oldBuf = NULL; char *newBuf = NULL; if (keychainName) { keychain = keychain_open(keychainName); if (!keychain) { result = 1; goto cleanup; } } if (!oldPass) { /* prompt for old password */ char *pBuf = getpass("Old Password: "******"New Password: "******"Retype New Password: "******"try again"); goto cleanup; } /* lock keychain first to remove existing credentials */ (void)SecKeychainLock(keychain); /* change the password */ result = SecKeychainChangePassword(keychain, oldLen, oldPass, newLen, newPass); if (result) { sec_error("error changing password for \"%s\": %s", keychainName ? keychainName : "<NULL>", sec_errstr(result)); } cleanup: /* if we allocated password buffers, zero and free them */ if (oldBuf) { bzero(oldBuf, PW_BUF_SIZE); free(oldBuf); } if (newBuf) { bzero(newBuf, PW_BUF_SIZE); free(newBuf); } if (keychain) { CFRelease(keychain); } return result; }
void sec_perror(const char *msg, int err) { sec_error("%s: %s", msg, sec_errstr(err)); }
int keychain_export(int argc, char * const *argv) { int ch, result = 0; char *outFile = NULL; char *kcName = NULL; SecKeychainRef kcRef = NULL; SecExternalFormat externFormat = kSecFormatUnknown; ItemSpec itemSpec = IS_All; int wrapped = 0; int doPem = 0; const char *passphrase = NULL; while ((ch = getopt(argc, argv, "k:o:t:f:P:wph")) != -1) { switch (ch) { case 'k': kcName = optarg; break; case 'o': outFile = optarg; break; case 't': if(!strcmp("certs", optarg)) { itemSpec = IS_Certs; } else if(!strcmp("allKeys", optarg)) { itemSpec = IS_AllKeys; } else if(!strcmp("pubKeys", optarg)) { itemSpec = IS_PubKeys; } else if(!strcmp("privKeys", optarg)) { itemSpec = IS_PrivKeys; } else if(!strcmp("identities", optarg)) { itemSpec = IS_Identities; } else if(!strcmp("all", optarg)) { itemSpec = IS_All; } else { return 2; /* @@@ Return 2 triggers usage message. */ } break; case 'f': if(!strcmp("openssl", optarg)) { externFormat = kSecFormatOpenSSL; } else if(!strcmp("openssh1", optarg)) { externFormat = kSecFormatSSH; } else if(!strcmp("openssh2", optarg)) { externFormat = kSecFormatSSHv2; } else if(!strcmp("bsafe", optarg)) { externFormat = kSecFormatBSAFE; } else if(!strcmp("raw", optarg)) { externFormat = kSecFormatRawKey; } else if(!strcmp("pkcs7", optarg)) { externFormat = kSecFormatPKCS7; } else if(!strcmp("pkcs8", optarg)) { externFormat = kSecFormatWrappedPKCS8; } else if(!strcmp("pkcs12", optarg)) { externFormat = kSecFormatPKCS12; } else if(!strcmp("netscape", optarg)) { externFormat = kSecFormatNetscapeCertSequence; } else if(!strcmp("x509", optarg)) { externFormat = kSecFormatX509Cert; } else if(!strcmp("pemseq", optarg)) { externFormat = kSecFormatPEMSequence; } else { return 2; /* @@@ Return 2 triggers usage message. */ } break; case 'w': wrapped = 1; break; case 'p': doPem = 1; break; case 'P': passphrase = optarg; break; case '?': default: return 2; /* @@@ Return 2 triggers usage message. */ } } if(wrapped) { switch(externFormat) { case kSecFormatOpenSSL: case kSecFormatUnknown: // i.e., use default externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatSSH: externFormat = kSecFormatWrappedSSH; break; case kSecFormatSSHv2: /* there is no wrappedSSHv2 */ externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatWrappedPKCS8: /* proceed */ break; default: sec_error("Don't know how to wrap in specified format/type"); return 2; /* @@@ Return 2 triggers usage message. */ } } if(kcName) { kcRef = keychain_open(kcName); if(kcRef == NULL) { return 1; } } result = do_keychain_export(kcRef, externFormat, itemSpec, passphrase, doPem, outFile); if(kcRef) { CFRelease(kcRef); } return result; }
int leaks(int argc, char *const *argv) { int result = 1; pid_t child; pid_t parent = getpid(); child = fork(); switch (child) { case -1: /* Fork failed we're hosed. */ sec_error("fork: %s", strerror(errno)); break; case 0: { /* child. */ char **argvec = (char **)malloc((argc + 2) * sizeof(char *)); char pidstr[8]; int ix; sprintf(pidstr, "%d", parent); argvec[0] = "/usr/bin/leaks"; for (ix = 1; ix < argc; ++ix) argvec[ix] = argv[ix]; argvec[ix] = pidstr; argvec[ix + 1] = NULL; execv(argvec[0], argvec); sec_error("exec: %s", strerror(errno)); _exit(1); break; } default: { /* Parent. */ int status = 0; for (;;) { /* Wait for the child to exit. */ pid_t waited_pid = waitpid(child, &status, 0); if (waited_pid == -1) { int error = errno; /* Keep going if we get interupted but bail out on any other error. */ if (error == EINTR) continue; sec_error("waitpid %d: %s", status, strerror(errno)); break; } if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { /* Force usage message. */ result = 2; sec_error("leaks exited: %d", result); } break; } else if (WIFSIGNALED(status)) { sec_error("leaks terminated by signal: %d", WTERMSIG(status)); break; } } break; } } return result; }
int keychain_import(int argc, char * const *argv) { int ch, result = 0; char *inFile = NULL; char *kcName = NULL; SecKeychainRef kcRef = NULL; SecExternalFormat externFormat = kSecFormatUnknown; SecExternalItemType itemType = kSecItemTypeUnknown; Boolean wrapped = FALSE; Boolean nonExtractable = FALSE; const char *passphrase = NULL; unsigned char *inFileData = NULL; unsigned inFileLen = 0; CFDataRef inData = NULL; unsigned numExtendedAttributes = 0; char **attrNames = NULL; char **attrValues = NULL; Boolean access_specified = FALSE; Boolean always_allow = FALSE; SecAccessRef access = NULL; CFMutableArrayRef trusted_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if(argc < 2) { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } inFile = argv[1]; if((argc == 2) && (inFile[0] == '-')) { result = 2; goto cleanup; } optind = 2; while ((ch = getopt(argc, argv, "k:t:f:P:wxa:hAT:")) != -1) { switch (ch) { case 'k': kcName = optarg; break; case 't': if(!strcmp("pub", optarg)) { itemType = kSecItemTypePublicKey; } else if(!strcmp("priv", optarg)) { itemType = kSecItemTypePrivateKey; } else if(!strcmp("session", optarg)) { itemType = kSecItemTypeSessionKey; } else if(!strcmp("cert", optarg)) { itemType = kSecItemTypeCertificate; } else if(!strcmp("agg", optarg)) { itemType = kSecItemTypeAggregate; } else { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } break; case 'f': if(!strcmp("openssl", optarg)) { externFormat = kSecFormatOpenSSL; } else if(!strcmp("openssh1", optarg)) { externFormat = kSecFormatSSH; } else if(!strcmp("openssh2", optarg)) { externFormat = kSecFormatSSHv2; } else if(!strcmp("bsafe", optarg)) { externFormat = kSecFormatBSAFE; } else if(!strcmp("raw", optarg)) { externFormat = kSecFormatRawKey; } else if(!strcmp("pkcs7", optarg)) { externFormat = kSecFormatPKCS7; } else if(!strcmp("pkcs8", optarg)) { externFormat = kSecFormatWrappedPKCS8; } else if(!strcmp("pkcs12", optarg)) { externFormat = kSecFormatPKCS12; } else if(!strcmp("netscape", optarg)) { externFormat = kSecFormatNetscapeCertSequence; } else if(!strcmp("x509", optarg)) { externFormat = kSecFormatX509Cert; } else if(!strcmp("pemseq", optarg)) { externFormat = kSecFormatPEMSequence; } else { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } break; case 'w': wrapped = TRUE; break; case 'x': nonExtractable = TRUE; break; case 'P': passphrase = optarg; break; case 'a': /* this takes an additional argument */ if(optind > (argc - 1)) { result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } attrNames = (char **)realloc(attrNames, numExtendedAttributes * sizeof(char *)); attrValues = (char **)realloc(attrValues, numExtendedAttributes * sizeof(char *)); attrNames[numExtendedAttributes] = optarg; attrValues[numExtendedAttributes] = argv[optind]; numExtendedAttributes++; optind++; break; case 'A': always_allow = TRUE; access_specified = TRUE; break; case 'T': if (optarg[0]) { SecTrustedApplicationRef app = NULL; OSStatus status = noErr; /* check whether the argument specifies an application group */ const char *groupPrefix = "group://"; size_t prefixLen = strlen(groupPrefix); if (strlen(optarg) > prefixLen && !memcmp(optarg, groupPrefix, prefixLen)) { const char *groupName = &optarg[prefixLen]; if ((status = SecTrustedApplicationCreateApplicationGroup(groupName, NULL, &app)) != noErr) { sec_error("SecTrustedApplicationCreateApplicationGroup %s: %s", optarg, sec_errstr(status)); } } else { if ((status = SecTrustedApplicationCreateFromPath(optarg, &app)) != noErr) { sec_error("SecTrustedApplicationCreateFromPath %s: %s", optarg, sec_errstr(status)); } } if (status) { result = 1; goto cleanup; } CFArrayAppendValue(trusted_list, app); CFRelease(app); } access_specified = TRUE; break; case '?': default: result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } } if(wrapped) { switch(externFormat) { case kSecFormatOpenSSL: case kSecFormatUnknown: // i.e., use default externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatSSH: externFormat = kSecFormatWrappedSSH; break; case kSecFormatSSHv2: /* there is no wrappedSSHv2 */ externFormat = kSecFormatWrappedOpenSSL; break; case kSecFormatWrappedPKCS8: /* proceed */ break; default: fprintf(stderr, "Don't know how to wrap in specified format/type\n"); result = 2; /* @@@ Return 2 triggers usage message. */ goto cleanup; } } if(kcName) { kcRef = keychain_open(kcName); if(kcRef == NULL) { return 1; } } if(readFile(inFile, &inFileData, &inFileLen)) { sec_error("Error reading infile %s: %s", inFile, strerror(errno)); result = 1; goto cleanup; } inData = CFDataCreate(NULL, inFileData, inFileLen); if(inData == NULL) { result = 1; goto cleanup; } free(inFileData); if(access_specified) { char *accessName = NULL; CFStringRef fileStr = CFStringCreateWithCString(NULL, inFile, kCFStringEncodingUTF8); if (fileStr) { CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, fileStr, kCFURLPOSIXPathStyle, FALSE); if (fileURL) { CFStringRef nameStr = CFURLCopyLastPathComponent(fileURL); if (nameStr) { CFIndex nameLen = CFStringGetLength(nameStr); CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); accessName = (char *)malloc(bufLen); if (!CFStringGetCString(nameStr, accessName, bufLen-1, kCFStringEncodingUTF8)) accessName[0]=0; nameLen = strlen(accessName); char *p = &accessName[nameLen]; // initially points to terminating null while (--nameLen > 0) { if (*p == '.') { // strip extension, if any *p = '\0'; break; } p--; } safe_CFRelease(&nameStr); } safe_CFRelease(&fileURL); } safe_CFRelease(&fileStr); } result = create_access(accessName, always_allow, trusted_list, &access); if (accessName) { free(accessName); } if (result != 0) { goto cleanup; } } result = do_keychain_import(kcRef, inData, externFormat, itemType, access, nonExtractable, passphrase, inFile, attrNames, attrValues, numExtendedAttributes); cleanup: safe_CFRelease(&trusted_list); safe_CFRelease(&access); safe_CFRelease(&kcRef); safe_CFRelease(&inData); return result; }
/* * Find private key by label, modify its Label attr to be the * hash of the associated public key. */ static CSSM_RETURN setPubKeyHash( CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE dlDbHand, const CSSM_KEY *pubOrPrivKey, // to get hash; raw or ref/CSPDL const char *keyLabel) // look up by this { CSSM_QUERY query; CSSM_SELECTION_PREDICATE predicate; CSSM_DB_UNIQUE_RECORD_PTR record = NULL; CSSM_RETURN crtn; CSSM_DATA labelData; CSSM_HANDLE resultHand; labelData.Data = (uint8 *)keyLabel; labelData.Length = strlen(keyLabel) + 1; // incl. NULL query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; query.Conjunctive = CSSM_DB_NONE; query.NumSelectionPredicates = 1; predicate.DbOperator = CSSM_DB_EQUAL; predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; predicate.Attribute.Info.Label.AttributeName = "Label"; predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; predicate.Attribute.Value = &labelData; query.SelectionPredicate = &predicate; query.QueryLimits.TimeLimit = 0; query.QueryLimits.SizeLimit = 1; query.QueryFlags = 0; /* build Record attribute with one attr */ CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; CSSM_DB_ATTRIBUTE_DATA attr; attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; attr.Info.Label.AttributeName = "Label"; attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; recordAttrs.NumberOfAttributes = 1; recordAttrs.AttributeData = &attr; crtn = CSSM_DL_DataGetFirst(dlDbHand, &query, &resultHand, &recordAttrs, NULL, // hopefully optional ...theData, &record); /* abort only on success */ if(crtn != CSSM_OK) { sec_error("CSSM_DL_DataGetFirst: setPubKeyHash: can't find private key: %s", sec_errstr(crtn)); return crtn; } /* * If specified key is a ref key, do NULL unwrap for use with raw CSP. * If the CSPDL and SecurityServer support the key digest passthrough * this is unnecessary. */ CSSM_KEY rawKeyToDigest; if(pubOrPrivKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE) { crtn = refKeyToRaw(cspHand, pubOrPrivKey, &rawKeyToDigest); if(crtn) { sec_error("setPubKeyHash: Error converting public key to raw format: %s", sec_errstr(crtn)); return crtn; } } else { /* use as is */ rawKeyToDigest = *pubOrPrivKey; } /* connect to raw CSP */ CSSM_CSP_HANDLE rawCspHand = srCspStartup(CSSM_TRUE); if(rawCspHand == 0) { printf("***Error connecting to raw CSP; aborting.\n"); return -1; } /* calculate hash of pub key from private or public part */ CSSM_DATA_PTR keyDigest = NULL; CSSM_CC_HANDLE ccHand; crtn = CSSM_CSP_CreatePassThroughContext(rawCspHand, &rawKeyToDigest, &ccHand); if(ccHand == 0) { sec_error("CSSM_CSP_CreatePassThroughContext: Error calculating public key hash. Aborting: %s", sec_errstr(crtn)); return -1; } crtn = CSSM_CSP_PassThrough(ccHand, CSSM_APPLECSP_KEYDIGEST, NULL, (void **)&keyDigest); if(crtn) { sec_error("CSSM_CSP_PassThrough(PUBKEYHASH): Error calculating public key hash. Aborting: %s", sec_errstr(crtn)); return crtn; } if(pubOrPrivKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE) { /* created in refKeyToRaw().... */ CSSM_FreeKey(cspHand, NULL, &rawKeyToDigest, CSSM_FALSE); } CSSM_DeleteContext(ccHand); CSSM_ModuleDetach(rawCspHand); /* * Replace Label attr data with hash. * NOTE: the module which allocated this attribute data - a DL - * was loaded and attached by the Sec layer, not by us. Thus * we can't use the memory allocator functions *we* used when * attaching to the CSPDL - we have to use the ones * which the Sec layer registered with the DL. */ CSSM_API_MEMORY_FUNCS memFuncs; crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs); if(crtn) { sec_error("CSSM_GetAPIMemoryFunctions(DLHandle): Error: %s", sec_errstr(crtn)); /* oh well, leak and continue */ } else { memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef); memFuncs.free_func(attr.Value, memFuncs.AllocRef); } attr.Value = keyDigest; /* modify key attributes */ crtn = CSSM_DL_DataModify(dlDbHand, CSSM_DL_DB_RECORD_PRIVATE_KEY, record, &recordAttrs, NULL, // DataToBeModified CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); if(crtn) { sec_error("CSSM_DL_DataModify(PUBKEYHASH): Error setting public key hash. Aborting: %s", sec_errstr(crtn)); return crtn; } crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand); if(crtn) { sec_error("CSSM_DL_DataAbortQuery: Error while stopping query: %s", sec_errstr(crtn)); /* let's keep going in this case */ } crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record); if(crtn) { sec_error("CSSM_DL_FreeUniqueRecord: Error while freeing record: %s", sec_errstr(crtn)); /* let's keep going in this case */ crtn = CSSM_OK; } /* free resources */ if (keyDigest) { srAppFree(keyDigest->Data, NULL); srAppFree(keyDigest, NULL); } return CSSM_OK; }
OSStatus createRootCert( CSSM_TP_HANDLE tpHand, CSSM_CL_HANDLE clHand, CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR subjPubKey, CSSM_KEY_PTR signerPrivKey, const char *hostName, // CSSMOID_CommonName const char *userName, // CSSMOID_Description CSSM_ALGORITHMS sigAlg, const CSSM_OID *sigOid, CSSM_DATA_PTR certData) // mallocd and RETURNED { CE_DataAndType exts[2]; CE_DataAndType *extp = exts; unsigned numExts; CSSM_DATA refId; // mallocd by // CSSM_TP_SubmitCredRequest CSSM_APPLE_TP_CERT_REQUEST certReq; CSSM_TP_REQUEST_SET reqSet; sint32 estTime; CSSM_BOOL confirmRequired; CSSM_TP_RESULT_SET_PTR resultSet=NULL; CSSM_ENCODED_CERT *encCert=NULL; CSSM_APPLE_TP_NAME_OID subjectNames[2]; CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; CSSM_FIELD policyId; numExts = 0; certReq.challengeString = NULL; /* KeyUsage extension */ extp->type = DT_KeyUsage; extp->critical = CSSM_FALSE; extp->extension.keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign | CE_KU_KeyEncipherment | CE_KU_DataEncipherment; extp++; numExts++; /* BasicConstraints */ extp->type = DT_BasicConstraints; extp->critical = CSSM_TRUE; extp->extension.basicConstraints.cA = CSSM_FALSE; extp->extension.basicConstraints.pathLenConstraintPresent = CSSM_FALSE; extp++; numExts++; /* name array */ subjectNames[0].string = hostName; subjectNames[0].oid = &CSSMOID_CommonName; subjectNames[1].string = userName; subjectNames[1].oid = &CSSMOID_Description; /* certReq */ certReq.cspHand = cspHand; certReq.clHand = clHand; randUint32(&certReq.serialNumber); // random serial number certReq.numSubjectNames = 2; certReq.subjectNames = subjectNames; certReq.numIssuerNames = 0; // root for now certReq.issuerNames = NULL; certReq.issuerNameX509 = NULL; certReq.certPublicKey = subjPubKey; certReq.issuerPrivateKey = signerPrivKey; certReq.signatureAlg = sigAlg; certReq.signatureOid = *sigOid; certReq.notBefore = 0; certReq.notAfter = 60 * 60 * 24 * 365; // seconds from now, one year certReq.numExtensions = numExts; certReq.extensions = exts; reqSet.NumberOfRequests = 1; reqSet.Requests = &certReq; /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */ memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); memset(&policyId, 0, sizeof(CSSM_FIELD)); policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; CallerAuthContext.Policy.NumberOfPolicyIds = 1; CallerAuthContext.Policy.PolicyIds = &policyId; CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand, NULL, // PreferredAuthority CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &CallerAuthContext, &estTime, &refId); if(crtn) { sec_error("CSSM_TP_SubmitCredRequest: %s", sec_errstr(crtn)); goto xit; } crtn = CSSM_TP_RetrieveCredResult(tpHand, &refId, NULL, // CallerAuthCredentials &estTime, &confirmRequired, &resultSet); if(crtn) { sec_error("CSSM_TP_RetrieveCredResult: %s", sec_errstr(crtn)); goto xit; } if(resultSet == NULL) { sec_error("CSSM_TP_RetrieveCredResult: returned NULL result set"); crtn = ioErr; goto xit; } encCert = (CSSM_ENCODED_CERT *)resultSet->Results; certData->Length = encCert->CertBlob.Length; certData->Data = malloc(encCert->CertBlob.Length); if (certData->Data) memcpy(certData->Data, encCert->CertBlob.Data, encCert->CertBlob.Length); crtn = noErr; xit: /* free resources allocated by TP */ APP_FREE(refId.Data); if (encCert) { if (encCert->CertBlob.Data) { APP_FREE(encCert->CertBlob.Data); } APP_FREE(encCert); } APP_FREE(resultSet); return crtn; }
static int do_recode(const char *keychainName1, const char *keychainName2) { SecKeychainRef keychain1 = NULL, keychain2 = NULL; CFMutableArrayRef dbBlobArray = NULL; CFDataRef dbBlob = NULL, extraData = NULL; OSStatus result; if (keychainName1) { keychain1 = keychain_open(keychainName1); if (!keychain1) { result = 1; goto loser; } } keychain2 = keychain_open(keychainName2); if (!keychain2) { result = 1; goto loser; } result = SecKeychainCopyBlob(keychain2, &dbBlob); if (result) { sec_error("SecKeychainCopyBlob %s: %s", keychainName2, sec_errstr(result)); goto loser; } extraData = CFDataCreate(NULL, NULL, 0); dbBlobArray = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); if (dbBlobArray) { CFArrayAppendValue(dbBlobArray, dbBlob); } #if !defined MAC_OS_X_VERSION_10_6 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 result = SecKeychainRecodeKeychain(keychain1, dbBlob, extraData); #else result = SecKeychainRecodeKeychain(keychain1, dbBlobArray, extraData); #endif if (result) sec_error("SecKeychainRecodeKeychain %s, %s: %s", keychainName1, keychainName2, sec_errstr(result)); loser: if (dbBlobArray) CFRelease(dbBlobArray); if (dbBlob) CFRelease(dbBlob); if (extraData) CFRelease(extraData); if (keychain1) CFRelease(keychain1); if (keychain2) CFRelease(keychain2); return result; }
int write_storage_proc(void *arg) { u8* data = 0; u32 data_len = 0; char msg[128]; u64 image_offset = 0; u32 round = 0; //dprintf(DBG_DCACHE, " --[%d] Enter write_storage_proc \n", TIME_STAMP); for (;;) { dprintf(DBG_DCACHE, " --[%d]Wait ID:%d cache to read, \n", TIME_STAMP, ctx.flipIdxR); event_wait(&(ctx.dual_cache[ctx.flipIdxR].content_available)); dprintf(DBG_DCACHE, " --[%d]Obtain ID:%d cache to read, \n", TIME_STAMP, ctx.flipIdxR); if(ctx.b_error) { sprintf(msg, "\nError USB?\n"); goto error; } //if has something to write if(ctx.dual_cache[ctx.flipIdxR].content_length !=0 || ctx.dual_cache[ctx.flipIdxR].padding_length !=0) { data = (u8*)(ctx.dual_cache[ctx.flipIdxR].cache_buf); data_len = ctx.dual_cache[ctx.flipIdxR].content_length; #ifdef MTK_SECURITY_SW_SUPPORT if(!security_check(&data, &data_len, image_offset, NULL)) { //security error. sprintf(msg, "\nSecurity deny - Err:0x%x \n", sec_error()); goto error; } #endif image_offset += ctx.dual_cache[ctx.flipIdxR].content_length; data -= ctx.dual_cache[ctx.flipIdxR].padding_length; data_len += ctx.dual_cache[ctx.flipIdxR].padding_length; //if data_len==0, secure img tail met. dprintf(DBG_DCACHE, " --[%d]Write ID:%d to EMMC \n", TIME_STAMP, ctx.flipIdxR); #ifdef MTK_SECURITY_SW_SUPPORT if(!write_data(data, data_len, sec_lib_security_get_img_total_size())) #else if(!write_data(data, data_len, 0)) #endif { //error sprintf(msg, "\nWrite data error. \n"); goto error; } } //last package, should return; if (ctx.dual_cache[ctx.flipIdxR].content_length == 0) { dprintf(DBG_DCACHE, " --[%d]Write EMMC Fin\n", TIME_STAMP); data_len = 0; #ifdef MTK_SECURITY_SW_SUPPORT security_check(&data, &data_len, image_offset, NULL); //notify security check that is the end. #endif if(ctx.boot_like_info.is_boot_like_image) { //boot image need download_size to flash. download_size = sto_info.to_write_data_len; //cache using is over, so copy boot image to download_base memcpy(download_base, ctx.boot_like_info.boot_like_image_address, download_size); } event_signal(&ctx.dual_cache[0].cache_available, SIGNAL_RESCHEDULE);//prevent from dead lock. event_signal(&ctx.dual_cache[1].cache_available, SIGNAL_RESCHEDULE); event_signal(&ctx.thr_end_ev, SIGNAL_RESCHEDULE); return 0; } round++; dprintf(DBG_DCACHE, " --[%d]Notify ID:%d cache writeable\n", TIME_STAMP, ctx.flipIdxR); event_signal(&ctx.dual_cache[ctx.flipIdxR].cache_available, SIGNAL_RESCHEDULE); //make this cache writeable again. ctx.flipIdxR = cache_shift(ctx.flipIdxR); //change next buffer. } return 0; error: dprintf(DBG_LV, msg); display_info(msg); abort_engine(&ctx); return (-1); }
// find_unique_certificate // // Returns a SecKeychainItemRef for the certificate // in the specified keychain (or keychain list) // which is a unique match for either the specified name // or SHA-1 hash. If more than one match exists, the // certificate is not unique and none are returned. Caller is // responsible for releasing the item (with CFRelease). // SecKeychainItemRef find_unique_certificate(CFTypeRef keychainOrArray, const char *name, const char *hash) { OSStatus status = noErr; SecKeychainSearchRef searchRef = NULL; SecKeychainItemRef uniqueItemRef = NULL; status = SecKeychainSearchCreateFromAttributes(keychainOrArray, kSecCertificateItemClass, NULL, &searchRef); if (status) { return uniqueItemRef; } // check input hash string and convert to data CSSM_DATA hashData = { 0, NULL }; if (hash) { CSSM_SIZE len = strlen(hash)/2; hashData.Length = len; hashData.Data = (uint8 *)malloc(hashData.Length); fromHex(hash, &hashData); } // filter candidates against the hash (or the name, if no hash provided) CFStringRef matchRef = (name) ? CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8) : NULL; Boolean exactMatch = FALSE; CSSM_DATA certData = { 0, NULL }; SecKeychainItemRef candidate = NULL; while (SecKeychainSearchCopyNext(searchRef, &candidate) == noErr) { SecCertificateRef cert = (SecCertificateRef)candidate; if (SecCertificateGetData(cert, &certData) != noErr) { safe_CFRelease(&candidate); continue; } if (hash) { uint8 candidate_sha1_hash[20]; CSSM_DATA digest; digest.Length = sizeof(candidate_sha1_hash); digest.Data = candidate_sha1_hash; if ((SecDigestGetData(CSSM_ALGID_SHA1, &digest, &certData) == CSSM_OK) && (hashData.Length == digest.Length) && (!memcmp(hashData.Data, digest.Data, digest.Length))) { exactMatch = TRUE; uniqueItemRef = candidate; // currently retained break; // we're done - can't get more exact than this } } else { // copy certificate name CFStringRef nameRef = NULL; if ((SecCertificateCopyCommonName(cert, &nameRef) != noErr) || nameRef == NULL) { safe_CFRelease(&candidate); continue; // no name, so no match is possible } CFIndex nameLen = CFStringGetLength(nameRef); CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); char *nameBuf = (char *)malloc(bufLen); if (!CFStringGetCString(nameRef, nameBuf, bufLen-1, kCFStringEncodingUTF8)) nameBuf[0]=0; CFRange find = { kCFNotFound, 0 }; if (nameRef && matchRef) find = CFStringFind(nameRef, matchRef, kCFCompareCaseInsensitive | kCFCompareNonliteral); Boolean isExact = (find.location == 0 && find.length == nameLen); if (find.location == kCFNotFound) { free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; // no match } if (uniqueItemRef) { // got two matches if (exactMatch && !isExact) { // prior is better; ignore this one free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; } if (exactMatch == isExact) { // same class of match if (CFEqual(uniqueItemRef, candidate)) { // same certificate free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; } // ambiguity - must fail sec_error("\"%s\" is ambiguous, matches more than one certificate", name); free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); safe_CFRelease(&uniqueItemRef); break; } safe_CFRelease(&uniqueItemRef); // about to replace with this one } uniqueItemRef = candidate; // currently retained exactMatch = isExact; free(nameBuf); safe_CFRelease(&nameRef); } } safe_CFRelease(&searchRef); safe_CFRelease(&matchRef); if (hashData.Data) { free(hashData.Data); } return uniqueItemRef; }
static int do_keychain_export( SecKeychainRef kcRef, SecExternalFormat externFormat, ItemSpec itemSpec, const char *passphrase, int doPem, const char *fileName) { int result = 0; CFIndex numItems; unsigned numPrivKeys = 0; unsigned numPubKeys = 0; unsigned numCerts = 0; unsigned numIdents = 0; OSStatus ortn; uint32 expFlags = 0; // SecItemImportExportFlags SecKeyImportExportParameters keyParams; CFStringRef passStr = NULL; CFDataRef outData = NULL; unsigned len; /* gather items */ CFMutableArrayRef exportItems = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); switch(itemSpec) { case IS_Certs: ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts); if(ortn) { result = 1; goto loser; } break; case IS_PrivKeys: ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems, &numPrivKeys); if(ortn) { result = 1; goto loser; } break; case IS_PubKeys: ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems, &numPubKeys); if(ortn) { result = 1; goto loser; } break; case IS_AllKeys: ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems, &numPrivKeys); if(ortn) { result = 1; goto loser; } ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems, &numPubKeys); if(ortn) { result = 1; goto loser; } break; case IS_All: /* No public keys here - PKCS12 doesn't support them */ ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts); if(ortn) { result = 1; goto loser; } ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems, &numPrivKeys); if(ortn) { result = 1; goto loser; } break; case IS_Identities: ortn = addIdentities(kcRef, exportItems, &numIdents); if(ortn) { result = 1; goto loser; } if(numIdents) { numPrivKeys += numIdents; numCerts += numIdents; } break; default: sec_error("Internal error parsing item_spec"); result = 1; goto loser; } numItems = CFArrayGetCount(exportItems); if(externFormat == kSecFormatUnknown) { /* Use default export format per set of items */ if(numItems > 1) { externFormat = kSecFormatPEMSequence; } else if(numCerts) { externFormat = kSecFormatX509Cert; } else { externFormat = kSecFormatOpenSSL; } } if(doPem) { expFlags |= kSecItemPemArmour; } /* * Key related arguments, ignored if we're not exporting keys. * Always specify some kind of passphrase - default is secure passkey. */ memset(&keyParams, 0, sizeof(keyParams)); keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; if(passphrase != NULL) { passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII); keyParams.passphrase = passStr; } else { keyParams.flags = kSecKeySecurePassphrase; } /* Go */ ortn = SecKeychainItemExport(exportItems, externFormat, expFlags, &keyParams, &outData); if(ortn) { sec_perror("SecKeychainItemExport", ortn); result = 1; goto loser; } len = CFDataGetLength(outData); if(fileName) { int rtn = writeFile(fileName, CFDataGetBytePtr(outData), len); if(rtn == 0) { if(!do_quiet) { fprintf(stderr, "...%u bytes written to %s\n", len, fileName); } } else { sec_error("Error writing to %s: %s", fileName, strerror(errno)); result = 1; } } else { int irtn = write(STDOUT_FILENO, CFDataGetBytePtr(outData), len); if(irtn != (int)len) { perror("write"); } } loser: if(exportItems) { CFRelease(exportItems); } if(passStr) { CFRelease(passStr); } if(outData) { CFRelease(outData); } return result; }
static int do_keychain_import( SecKeychainRef kcRef, CFDataRef inData, SecExternalFormat externFormat, SecExternalItemType itemType, SecAccessRef access, Boolean nonExtractable, const char *passphrase, const char *fileName, char **attrNames, char **attrValues, unsigned numExtendedAttributes) { SecKeyImportExportParameters keyParams; OSStatus ortn; CFStringRef fileStr; CFArrayRef outArray = NULL; int result = 0; int numCerts = 0; int numKeys = 0; int numIdentities = 0; int tryCount = 0; CFIndex dex; CFIndex numItems = 0; CFStringRef passStr = NULL; CFStringRef promptStr = NULL; CFStringRef retryStr = NULL; /* * Specify some kind of passphrase in case caller doesn't know this * is a wrapped object */ memset(&keyParams, 0, sizeof(SecKeyImportExportParameters)); keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; if(passphrase != NULL) { passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII); keyParams.passphrase = passStr; } else { keyParams.flags = kSecKeySecurePassphrase; } if(nonExtractable) { // explicitly set the key attributes, omitting the CSSM_KEYATTR_EXTRACTABLE bit keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE; } keyParams.accessRef = access; fileStr = CFStringCreateWithCString(NULL, fileName, kCFStringEncodingUTF8); if (fileStr) { CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, fileStr, kCFURLPOSIXPathStyle, FALSE); if (fileURL) { CFStringRef nameStr = CFURLCopyLastPathComponent(fileURL); if (nameStr) { safe_CFRelease(&fileStr); fileStr = nameStr; } safe_CFRelease(&fileURL); } } promptStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_MESSAGE, fileStr); retryStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_RETRYMESSAGE, fileStr); while (TRUE) { keyParams.alertPrompt = (tryCount == 0) ? promptStr : retryStr; ortn = SecKeychainItemImport(inData, fileStr, &externFormat, &itemType, 0, /* flags not used (yet) */ &keyParams, kcRef, &outArray); if(ortn) { if (ortn == errSecPkcs12VerifyFailure && ++tryCount < 3) { continue; } sec_perror("SecKeychainItemImport", ortn); result = 1; goto cleanup; } break; } /* * Parse returned items & report to user */ if(outArray == NULL) { sec_error("No keychain items found"); result = 1; goto cleanup; } numItems = CFArrayGetCount(outArray); for(dex=0; dex<numItems; dex++) { CFTypeRef item = CFArrayGetValueAtIndex(outArray, dex); CFTypeID itemType = CFGetTypeID(item); if(itemType == SecIdentityGetTypeID()) { numIdentities++; } else if(itemType == SecCertificateGetTypeID()) { numCerts++; } else if(itemType == SecKeyGetTypeID()) { numKeys++; } else { sec_error("Unexpected item type returned from SecKeychainItemImport"); result = 1; goto cleanup; } } if(numIdentities) { char *str; if(numIdentities > 1) { str = "identities"; } else { str = "identity"; } fprintf(stdout, "%d %s imported.\n", numIdentities, str); } if(numKeys) { char *str; if(numKeys > 1) { str = "keys"; } else { str = "key"; } fprintf(stdout, "%d %s imported.\n", numKeys, str); } if(numCerts) { char *str; if(numCerts > 1) { str = "certificates"; } else { str = "certificate"; } fprintf(stdout, "%d %s imported.\n", numCerts, str); } /* optionally apply extended attributes */ if(numExtendedAttributes) { unsigned attrDex; for(attrDex=0; attrDex<numExtendedAttributes; attrDex++) { CFStringRef attrNameStr = CFStringCreateWithCString(NULL, attrNames[attrDex], kCFStringEncodingASCII); CFDataRef attrValueData = CFDataCreate(NULL, (const UInt8 *)attrValues[attrDex], strlen(attrValues[attrDex])); for(dex=0; dex<numItems; dex++) { SecKeychainItemRef itemRef = (SecKeychainItemRef)CFArrayGetValueAtIndex(outArray, dex); ortn = SecKeychainItemSetExtendedAttribute(itemRef, attrNameStr, attrValueData); if(ortn) { cssmPerror("SecKeychainItemSetExtendedAttribute", ortn); result = 1; break; } } /* for each imported item */ CFRelease(attrNameStr); CFRelease(attrValueData); if(result) { break; } } /* for each extended attribute */ } cleanup: safe_CFRelease(&fileStr); safe_CFRelease(&outArray); safe_CFRelease(&passStr); safe_CFRelease(&promptStr); safe_CFRelease(&retryStr); return result; }
/* Read the file name into buffer. On return buffer contains a newly malloced buffer or length buffer_size. Return 0 on success and -1 on failure. */ int read_file(const char *name, CSSM_DATA *outData) { int fd, result; char *buffer = NULL; off_t length; ssize_t bytes_read; do { fd = open(name, O_RDONLY, 0); } while (fd == -1 && errno == EINTR); if (fd == -1) { sec_error("open %s: %s", name, strerror(errno)); result = -1; goto loser; } length = lseek(fd, 0, SEEK_END); if (length == -1) { sec_error("lseek %s, SEEK_END: %s", name, strerror(errno)); result = -1; goto loser; } buffer = malloc(length); do { bytes_read = pread(fd, buffer, length, 0); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == -1) { sec_error("pread %s: %s", name, strerror(errno)); result = -1; goto loser; } if (bytes_read != (ssize_t)length) { sec_error("read %s: only read %d of %qu bytes", name, bytes_read, length); result = -1; goto loser; } do { result = close(fd); } while (result == -1 && errno == EINTR); if (result == -1) { sec_error("close %s: %s", name, strerror(errno)); goto loser; } outData->Data = (uint8 *)buffer; outData->Length = (uint32)length; return result; loser: if (buffer) free(buffer); return result; }