X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/SecurityTests/cspxutils/pubKeyTool/pubKeyTool.cpp diff --git a/SecurityTests/cspxutils/pubKeyTool/pubKeyTool.cpp b/SecurityTests/cspxutils/pubKeyTool/pubKeyTool.cpp deleted file mode 100644 index ce53b0eb..00000000 --- a/SecurityTests/cspxutils/pubKeyTool/pubKeyTool.cpp +++ /dev/null @@ -1,672 +0,0 @@ -/* - * pubKeyTool.cpp - calculate public key hash of arbitrary keys and certs; derive - * public key from a private key or a cert. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "cspwrap.h" -#include "common.h" - -static void usage(char **argv) -{ - printf("usage: %s [options]\n", argv[0]); - printf("Options:\n"); - printf(" -k priv_key_file -- private key file to read\n"); - printf(" -b pub_key_file -- public key file to read\n"); - printf(" -c cert_file -- cert file to read\n"); - printf(" -d -- print public key digest\n"); - printf(" -o out_file -- write public key to out_file\n"); - printf(" -f pkcs1|pkcs8|x509 -- input key format\n"); - printf(" -- default is PKCS8 for private key, PKCS1 for" - " public\n"); - printf(" -K keychain -- import pub key to this keychain; workaround " - "for Radar 4191851)\n"); - exit(1); -} - -/* Convert raw key blob into a respectable CSSM_KEY. */ -static CSSM_RETURN inferCssmKey( - const CSSM_DATA &keyBlob, - bool isPrivKey, - CSSM_KEYBLOB_FORMAT keyForm, - CSSM_CSP_HANDLE cspHand, - CSSM_KEY &outKey) -{ - memset(&outKey, 0, sizeof(CSSM_KEY)); - outKey.KeyData = keyBlob; - CSSM_KEYHEADER &hdr = outKey.KeyHeader; - hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; - /* CspId blank */ - hdr.BlobType = CSSM_KEYBLOB_RAW; - hdr.AlgorithmId = CSSM_ALGID_RSA; - hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; - hdr.Format = keyForm; - hdr.KeyClass = isPrivKey ? CSSM_KEYCLASS_PRIVATE_KEY : CSSM_KEYCLASS_PUBLIC_KEY; - hdr.KeyUsage = CSSM_KEYUSE_ANY; - hdr.WrapAlgorithmId = CSSM_ALGID_NONE; - hdr.WrapMode = CSSM_ALGMODE_NONE; - /* - * LogicalKeySizeInBits - ask the CSP - */ - CSSM_KEY_SIZE keySize; - CSSM_RETURN crtn; - crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, &outKey, - &keySize); - if(crtn) { - cssmPerror("CSSM_QueryKeySizeInBits", crtn); - return crtn; - } - hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; - return CSSM_OK; -} - -/* - * Given any key in either blob or reference format, - * obtain the associated public key's SHA-1 hash. - */ -static CSSM_RETURN keyDigest( - CSSM_CSP_HANDLE cspHand, - const CSSM_KEY *key, - CSSM_DATA_PTR *hashData) /* struct and contents cuAppMalloc'd and RETURNED */ -{ - CSSM_CC_HANDLE ccHand; - CSSM_RETURN crtn; - CSSM_DATA_PTR dp; - - *hashData = NULL; - - /* validate input params */ - if((key == NULL) || - (hashData == NULL)) { - printf("keyHash: bogus args\n"); - return CSSMERR_CSSM_INTERNAL_ERROR; - } - - /* cook up a context for a passthrough op */ - crtn = CSSM_CSP_CreatePassThroughContext(cspHand, - key, - &ccHand); - if(ccHand == 0) { - cssmPerror("CSSM_CSP_CreatePassThroughContext", crtn); - return crtn; - } - - /* now it's up to the CSP */ - crtn = CSSM_CSP_PassThrough(ccHand, - CSSM_APPLECSP_KEYDIGEST, - NULL, - (void **)&dp); - if(crtn) { - cssmPerror("CSSM_CSP_PassThrough(KEYDIGEST)", crtn); - } - else { - *hashData = dp; - crtn = CSSM_OK; - } - CSSM_DeleteContext(ccHand); - return crtn; -} - -/* - * Here's a tricky one. Given a private key, obtain the correspoding public key. - * This uses a private key blob format that's used internally in the CSP - * to generate key digests. - */ - -/* - * this magic const copied from BinaryKey.h - */ -#define CSSM_KEYBLOB_RAW_FORMAT_DIGEST \ - (CSSM_KEYBLOB_RAW_FORMAT_VENDOR_DEFINED + 0x12345) - -static CSSM_RETURN pubKeyFromPrivKey( - CSSM_CSP_HANDLE cspHand, - const CSSM_KEY *privKey, // assumed to be raw format - CSSM_KEY *pubKey) -{ - /* first convert to reference key */ - CSSM_KEY refKey; - CSSM_RETURN crtn; - crtn = cspRawKeyToRef(cspHand, privKey, &refKey); - if(crtn) { - return crtn; - } - - /* now a NULL wrap with the magic format attribute */ - CSSM_CC_HANDLE ccHand; - CSSM_ACCESS_CREDENTIALS creds; - CSSM_DATA descData = {0, 0}; - - crtn = CSSM_CSP_CreateSymmetricContext(cspHand, - CSSM_ALGID_NONE, - CSSM_ALGMODE_NONE, - NULL, // passPhrase, - NULL, // key - NULL, // initVector, - CSSM_PADDING_NONE, - NULL, // Reserved - &ccHand); - if(crtn) { - cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); - return crtn; - } - crtn = AddContextAttribute(ccHand, - /* - * The output of the WrapKey is a private key as far as the CSP is - * concerned, at the level that this attribute is used anyway.... - */ - CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT, - sizeof(uint32), - CAT_Uint32, - NULL, - CSSM_KEYBLOB_RAW_FORMAT_DIGEST); - if(crtn) { - cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); - goto errOut; - } - memset(pubKey, 0, sizeof(CSSM_KEY)); - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - crtn = CSSM_WrapKey(ccHand, - &creds, - &refKey, - &descData, - pubKey); - if(crtn) { - cssmPerror("CSSM_WrapKey", crtn); - goto errOut; - } - - /* now: presto chango - don't do this at home! */ - pubKey->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; -errOut: - CSSM_FreeKey(cspHand, NULL, &refKey, CSSM_FALSE); - CSSM_DeleteContext(ccHand); - return crtn; -} - -/* - * Import a key into a DLDB. - */ -static CSSM_RETURN importToDlDb( - CSSM_CSP_HANDLE cspHand, - CSSM_DL_DB_HANDLE_PTR dlDbHand, - const CSSM_KEY *rawPubKey, - CSSM_DATA_PTR labelData, - CSSM_KEY_PTR importedKey) -{ - CSSM_CC_HANDLE ccHand = 0; - CSSM_RETURN crtn; - uint32 keyAttr; - CSSM_ACCESS_CREDENTIALS creds; - CSSM_CONTEXT_ATTRIBUTE newAttr; - CSSM_DATA descData = {0, 0}; - - memset(importedKey, 0, sizeof(CSSM_KEY)); - memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); - crtn = CSSM_CSP_CreateSymmetricContext(cspHand, - CSSM_ALGID_NONE, - CSSM_ALGMODE_NONE, - &creds, - NULL, // unwrappingKey - NULL, // initVector - CSSM_PADDING_NONE, - 0, // Params - &ccHand); - if(crtn) { - cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); - return crtn; - } - keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT; - - /* Add DLDB to context */ - newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE; - newAttr.AttributeLength = sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE); - newAttr.Attribute.Data = (CSSM_DATA_PTR)dlDbHand; - crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr); - if(crtn) { - cssmPerror("CSSM_UpdateContextAttributes", crtn); - goto errOut; - } - - /* import */ - crtn = CSSM_UnwrapKey(ccHand, - NULL, // PublicKey - rawPubKey, - CSSM_KEYUSE_ANY, - keyAttr, - labelData, - NULL, // CredAndAclEntry - importedKey, - &descData); // required - if(crtn) { - cssmPerror("CSSM_UnwrapKey", crtn); - } -errOut: - if(ccHand) { - CSSM_DeleteContext(ccHand); - } - return crtn; -} - -/* - * Free memory via specified plugin's app-level allocator - */ -void impExpFreeCssmMemory( - CSSM_HANDLE hand, - void *p) -{ - CSSM_API_MEMORY_FUNCS memFuncs; - CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs); - if(crtn) { - return; - } - memFuncs.free_func(p, memFuncs.AllocRef); -} - -/* - * Key attrribute names and values. - * - * This is where the public key hash goes. - */ -#define SEC_KEY_HASH_ATTR_NAME "Label" - -/* - * This is where the publicly visible name goes. - */ -#define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName" - -/* - * Look up public key by label - * Set label to new specified label (SHA1 digest) - * Set print name to new specified user-visible name - */ -static CSSM_RETURN setPubKeyLabel( - CSSM_CSP_HANDLE cspHand, // where the key lives - CSSM_DL_DB_HANDLE *dlDbHand, // ditto - const CSSM_DATA *existKeyLabel, // existing label, a random string, for lookup - const CSSM_DATA *keyDigest, // SHA1 digest, the new label - const CSSM_DATA *newPrintName) // new user-visible name -{ - CSSM_QUERY query; - CSSM_SELECTION_PREDICATE predicate; - CSSM_DB_UNIQUE_RECORD_PTR record = NULL; - CSSM_RETURN crtn; - CSSM_HANDLE resultHand = 0; - - /* - * Look up the key in the DL. - */ - query.RecordType = CSSM_DL_DB_RECORD_PUBLIC_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 = (char *)"Label"; - predicate.Attribute.Info.AttributeFormat = - CSSM_DB_ATTRIBUTE_FORMAT_BLOB; - /* hope this cast is OK */ - predicate.Attribute.Value = (CSSM_DATA_PTR)existKeyLabel; - query.SelectionPredicate = &predicate; - - query.QueryLimits.TimeLimit = 0; // FIXME - meaningful? - query.QueryLimits.SizeLimit = 1; // FIXME - meaningful? - query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used? - - /* build Record attribute with two attrs */ - CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; - CSSM_DB_ATTRIBUTE_DATA attr[2]; - - attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; - attr[0].Info.Label.AttributeName = (char *)SEC_KEY_HASH_ATTR_NAME; - attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; - attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; - attr[1].Info.Label.AttributeName = (char *)SEC_KEY_PRINT_NAME_ATTR_NAME; - attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; - - recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; - recordAttrs.NumberOfAttributes = 2; - recordAttrs.AttributeData = attr; - - crtn = CSSM_DL_DataGetFirst(*dlDbHand, - &query, - &resultHand, - &recordAttrs, - NULL, // theData - &record); - /* abort only on success */ - if(crtn != CSSM_OK) { - cssmPerror("CSSM_DL_DataGetFirst", crtn); - goto errOut; - } - - /* - * Update existing attr data. - * NOTE: the module which allocated this attribute data - a DL - - * was loaded and attached by the keychain layer, not by us. Thus - * we can't use the memory allocator functions *we* used when - * attaching to the CSP - we have to use the ones - * which the client registered with the DL. - */ - impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value->Data); - impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value); - impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value->Data); - impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value); - attr[0].Value = const_cast(keyDigest); - attr[1].Value = const_cast(newPrintName); - - crtn = CSSM_DL_DataModify(*dlDbHand, - CSSM_DL_DB_RECORD_PUBLIC_KEY, - record, - &recordAttrs, - NULL, // DataToBeModified - CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); - if(crtn) { - cssmPerror("CSSM_DL_DataModify", crtn); - } -errOut: - /* free resources */ - if(resultHand) { - CSSM_DL_DataAbortQuery(*dlDbHand, resultHand); - } - if(record) { - CSSM_DL_FreeUniqueRecord(*dlDbHand, record); - } - return crtn; -} - -#define SHA1_LABEL_LEN 20 -#define IMPORTED_KEY_NAME "Imported Public Key" - -/* - * Import a public key into a keychain, with proper Label attribute setting. - * A workaround for Radar 4191851. - */ -static int pubKeyImport( - const char *kcName, - const CSSM_KEY *pubKey, - CSSM_CSP_HANDLE rawCspHand) /* raw CSP handle for calculating digest */ -{ - CSSM_CSP_HANDLE cspHand; - CSSM_DL_DB_HANDLE dlDbHand; - OSStatus ortn; - CSSM_RETURN crtn; - SecKeychainRef kcRef = NULL; - int ourRtn = 0; - CSSM_DATA_PTR digest = NULL; - CSSM_KEY importedKey; - CSSM_DATA newPrintName = - { (uint32)strlen(IMPORTED_KEY_NAME), (uint8 *)IMPORTED_KEY_NAME}; - - /* NULL unwrap stuff */ - uint8 tempLabel[SHA1_LABEL_LEN]; - CSSM_DATA labelData = {SHA1_LABEL_LEN, tempLabel}; - - ortn = SecKeychainOpen(kcName, &kcRef); - if(ortn) { - cssmPerror("SecKeychainOpen", ortn); - return -1; - } - /* subsequent errors to errOut: */ - - /* Get CSSM handles */ - ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); - if(ortn) { - cssmPerror("SecKeychainGetCSPHandle", ortn); - ourRtn = -1; - goto errOut; - } - ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand); - if(ortn) { - cssmPerror("SecKeychainGetCSPHandle", ortn); - ourRtn = -1; - goto errOut; - } - - /* public key hash from raw CSP */ - crtn = keyDigest(rawCspHand, pubKey, &digest); - if(crtn) { - ourRtn = -1; - goto errOut; - } - - /* random label for initial storage and later retrieval */ - appGetRandomBytes(tempLabel, SHA1_LABEL_LEN); - - /* import the key into the keychain's DLDB */ - memset(&importedKey, 0, sizeof(CSSM_KEY)); - crtn = importToDlDb(cspHand, &dlDbHand, pubKey, &labelData, &importedKey); - if(crtn) { - ourRtn = -1; - goto errOut; - } - - /* don't need this */ - CSSM_FreeKey(cspHand, NULL, &importedKey, CSSM_FALSE); - - /* update the label and printName attributes */ - crtn = setPubKeyLabel(cspHand, &dlDbHand, &labelData, digest, &newPrintName); - if(crtn) { - ourRtn = -1; - } -errOut: - CFRelease(kcRef); - if(digest) { - APP_FREE(digest->Data); - APP_FREE(digest); - } - return ourRtn; -} - -int main(int argc, char **argv) -{ - char *privKeyFile = NULL; - char *pubKeyFile = NULL; - char *certFile = NULL; - char *outFile = NULL; - bool printDigest = false; - CSSM_KEYBLOB_FORMAT keyForm = CSSM_KEYBLOB_RAW_FORMAT_NONE; - char *kcName = NULL; - - if(argc < 3) { - usage(argv); - } - extern char *optarg; - int arg; - while ((arg = getopt(argc, argv, "k:b:c:do:f:K:h")) != -1) { - switch (arg) { - case 'k': - privKeyFile = optarg; - break; - case 'b': - pubKeyFile = optarg; - break; - case 'c': - certFile = optarg; - break; - case 'd': - printDigest = true; - break; - case 'o': - outFile = optarg; - break; - case 'f': - if(!strcmp("pkcs1", optarg)) { - keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; - } - else if(!strcmp("pkcs8", optarg)) { - keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; - } - else if(!strcmp("x509", optarg)) { - keyForm = CSSM_KEYBLOB_RAW_FORMAT_X509; - } - break; - case 'K': - kcName = optarg; - break; - case 'h': - usage(argv); - } - } - if(optind != argc) { - usage(argv); - } - - CSSM_DATA privKeyBlob = {0, NULL}; - CSSM_DATA pubKeyBlob = {0, NULL}; - CSSM_KEY thePrivKey; // constructed - CSSM_KEY thePubKey; // null-wrapped - CSSM_KEY_PTR pubKey = NULL; - CSSM_KEY_PTR privKey = NULL; - CSSM_RETURN crtn; - CSSM_CL_HANDLE clHand = 0; - CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_TRUE); - - /* gather input */ - if(privKeyFile) { - /* key blob from a file ==> a private CSSM_KEY */ - - if(pubKeyFile || certFile) { - printf("****Specify exactly one of {cert_file, priv_key_file, " - "pub_key_file}.\n"); - exit(1); - } - unsigned len; - if(readFile(privKeyFile, &privKeyBlob.Data, &len)) { - printf("***Error reading private key from %s. Aborting.\n", privKeyFile); - exit(1); - } - privKeyBlob.Length = len; - if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { - /* default for private keys */ - keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; - } - crtn = inferCssmKey(privKeyBlob, true, keyForm, cspHand, thePrivKey); - if(crtn) { - goto errOut; - } - privKey = &thePrivKey; - } - if(pubKeyFile) { - /* key blob from a file ==> a public CSSM_KEY */ - - if(privKeyFile || certFile) { - printf("****Specify exactly one of {cert_file, priv_key_file, " - "pub_key_file}.\n"); - exit(1); - } - - unsigned len; - if(readFile(pubKeyFile, &pubKeyBlob.Data, &len)) { - printf("***Error reading public key from %s. Aborting.\n", pubKeyFile); - exit(1); - } - pubKeyBlob.Length = len; - if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { - /* default for public keys */ - keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; - } - crtn = inferCssmKey(pubKeyBlob, false, keyForm, cspHand, thePubKey); - if(crtn) { - goto errOut; - } - pubKey = &thePubKey; - } - if(certFile) { - /* cert from a file ==> a public CSSM_KEY */ - - if(privKeyFile || pubKeyFile) { - printf("****Specify exactly one of {cert_file, priv_key_file, " - "pub_key_file}.\n"); - exit(1); - } - - CSSM_DATA certData = {0, NULL}; - unsigned len; - if(readFile(certFile, &certData.Data, &len)) { - printf("***Error reading cert from %s. Aborting.\n", certFile); - exit(1); - } - certData.Length = len; - - /* Extract public key - that's what we will be using later */ - clHand = cuClStartup(); - crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey); - if(crtn) { - cssmPerror("CSSM_CL_CertGetKeyInfo", crtn); - goto errOut; - } - } - - /* now do something useful */ - if(printDigest) { - CSSM_KEY_PTR theKey = privKey; - if(theKey == NULL) { - /* maybe we got public key from a cert */ - theKey = pubKey; - } - if(theKey == NULL) { - printf("***Can't calculate digest because I don't have a key or a clue.\n"); - goto errOut; - } - CSSM_DATA_PTR dig = NULL; - crtn = keyDigest(cspHand, theKey, &dig); - if(crtn) { - printf("Sorry, can't get the digest for this key.\n"); - goto errOut; - } - if((dig == NULL) || (dig->Length == 0)) { - printf("Screwup calculating digest.\n"); - goto errOut; - } - printf("Key Digest:\n"); - for(unsigned dex=0; dexLength; dex++) { - printf("%02X ", dig->Data[dex]); - } - printf("\n"); - APP_FREE(dig->Data); - APP_FREE(dig); - } - - if(outFile || kcName) { - /* get a public key if we don't already have one */ - if(pubKey == NULL) { - if(privKey == NULL) { - printf("***PubKey file name specified but no privKey or cert. " - "Aborting.\n"); - goto errOut; - } - crtn = pubKeyFromPrivKey(cspHand, privKey, &thePubKey); - if(crtn) { - goto errOut; - } - pubKey = &thePubKey; - } - } - if(outFile) { - if(writeFile(outFile, pubKey->KeyData.Data, pubKey->KeyData.Length)) { - printf("***Error writing to %s.\n", outFile); - } - else { - printf("...%lu bytes written to %s.\n", pubKey->KeyData.Length, outFile); - } - } - if(kcName) { - if(pubKeyImport(kcName, pubKey, cspHand) == 0) { - printf("....public key %s imported to %s\n", pubKeyFile, kcName); - } - else { - printf("***Error importing public key %s to %s\n", pubKeyFile, kcName); - } - } -errOut: - /* clean up here if you must */ - return 0; -}