X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/SecurityTests/clxutils/newCmsTool/newCmsTool.cpp?ds=inline diff --git a/SecurityTests/clxutils/newCmsTool/newCmsTool.cpp b/SecurityTests/clxutils/newCmsTool/newCmsTool.cpp deleted file mode 100644 index 3398e1b4..00000000 --- a/SecurityTests/clxutils/newCmsTool/newCmsTool.cpp +++ /dev/null @@ -1,1658 +0,0 @@ -/* - * cmstool.cpp - manipulate CMS messages, CMSEncoder/CMSDecoder version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* SecTrustGetCssmResultCode */ -#include /* SecIdentityCreateWithCertificate */ -#include -#include -#include - -#include -#include - -#define CFRELEASE(cfr) if(cfr != NULL) { CFRelease(cfr); } - -static SecKeychainRef keychain_open(const char *name); - -static void usage(char **argv) -{ - printf("Usage: %s cmd [option ...]\n", argv[0]); - printf("cmd values:\n"); - printf(" sign -- create signedData\n"); - printf(" envel -- create envelopedData\n"); - printf(" signEnv -- create nested EnvelopedData(signedData(data))\n"); - printf(" certs -- create certs-only CMS msg\n"); - printf(" parse -- parse a CMS message file\n"); - printf("Input/output options:\n"); - printf(" -i infile\n"); - printf(" -o outfile\n"); - printf(" -D detachedContent -- detached content (parse only)\n"); - printf(" -d detached -- infile contains detached content (sign only)\n"); - printf(" -f certFileBase -- dump all certs to certFileBase\n"); - printf("Signer and recipient options:\n"); - printf(" -k keychain -- Keychain to search for certs\n"); - printf(" -p -- Use identity picker\n"); - printf(" -r recipient -- add recipient (via email address) of enveloped data\n"); - printf(" -R recipCertFile -- add recipient (via cert from file) of enveloped data\n"); - printf(" -S signerEmail -- add signer email address\n"); - printf(" -C cert -- add (general) signedData cert\n"); - printf("Misc. options:\n"); - printf(" -e eContentType -- a(uthData)|r(keyData)\n"); - printf(" -m -- multi updates; default is one-shot\n"); - printf(" -1 (one) -- custom encoder/decoder\n"); - printf(" -2 -- fetch SecCmsMessageRef\n"); - printf(" -c -- parse signer certs\n"); - printf(" -a [ceEt] -- Signed Attributes: c=SmimeCaps,\n"); - printf(" e=EncrPrefs, E=MSEncrPrefs, t=signingTime\n"); - printf(" -A anchorFile -- Verify certs using specified anchor cert\n"); - printf(" -M -- Do SecTrustEvaluate manually\n"); - printf(" -t certChainMode -- none|signer|chain|chainWithRoot; default is chain\n"); - printf(" -l -- loop & pause for malloc debug\n"); - printf(" -q -- quiet\n"); - printf(" -Z -- silent, no output at all except for errors\n"); - printf("Verification options:\n"); - printf(" -v sign|encr|signEnv -- verify message is signed/encrypted/both\n"); - printf(" -s numSigners -- verify msg has specified number of signers\n"); - printf(" -E eContentType -- verify a(authData)|r(keyData)|d(data)\n"); - printf(" -N numCerts -- verify number of certs\n"); - exit(1); -} - -/* high level op */ -typedef enum { - CTO_Sign, - CTO_Envelop, - CTO_SignEnvelop, - CTO_CertsOnly, - CTO_Parse -} CT_Op; - -/* to verify */ -typedef enum { - CTV_None, - CTV_Sign, - CTV_Envelop, - CTV_SignEnvelop -} CT_Vfy; - -/* additional OIDS to specify as eContentType */ -#define OID_PKINIT 0x2B, 6, 1, 5, 2, 3 -#define OID_PKINIT_LEN 6 - -static const uint8 OID_PKINIT_AUTH_DATA[] = {OID_PKINIT, 1}; -static const uint8 OID_PKINIT_DH_KEY_DATA[] = {OID_PKINIT, 2}; -static const uint8 OID_PKINIT_RKEY_DATA[] = {OID_PKINIT, 3}; -static const uint8 OID_PKINIT_KP_CLIENTAUTH[] = {OID_PKINIT, 3}; -static const uint8 OID_PKINIT_KPKDC[] = {OID_PKINIT, 5}; - -static const CSSM_OID CSSMOID_PKINIT_AUTH_DATA = - {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_AUTH_DATA}; -static const CSSM_OID CSSMOID_PKINIT_DH_KEY_DATA = - {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_DH_KEY_DATA}; -static const CSSM_OID CSSMOID_PKINIT_RKEY_DATA = - {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_RKEY_DATA}; -static const CSSM_OID CSSMOID_PKINIT_KP_CLIENTAUTH = - {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_KP_CLIENTAUTH}; -static const CSSM_OID CSSMOID_PKINIT_KPKDC = - {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_KPKDC}; - -/* - * Find a cert in specified keychain or keychain list matching specified - * email address. We happen to know that the email address is stored with the - * kSecAlias attribute. - */ -static OSStatus findCert( - const char *emailAddress, - CFTypeRef kcArArray, // kc, array, or even NULL - SecCertificateRef *cert) -{ - OSStatus ortn; - SecKeychainSearchRef srch; - SecKeychainAttributeList attrList; - SecKeychainAttribute attr; - - attr.tag = kSecAlias; - attr.length = strlen(emailAddress); - attr.data = (void *)emailAddress; - attrList.count = 1; - attrList.attr = &attr; - - ortn = SecKeychainSearchCreateFromAttributes(kcArArray, - kSecCertificateItemClass, - &attrList, - &srch); - if(ortn) { - cssmPerror("SecKeychainSearchCreateFromAttributes", ortn); - return ortn; - } - - ortn = SecKeychainSearchCopyNext(srch, (SecKeychainItemRef *)cert); - if(ortn) { - printf("***No certs found matching recipient %s. Aborting.\n", - emailAddress); - return ortn; - } - CFRelease(srch); - return noErr; -} - -/* create a SecCertificateRef from a file */ -static SecCertificateRef readCertFile( - const char *fileName) -{ - unsigned char *certData = NULL; - unsigned certDataLen; - SecCertificateRef rtnCert = NULL; - - if(readFile(fileName, &certData, &certDataLen)) { - printf("***Error reading %s. Aborting.\n", fileName); - return NULL; - } - CSSM_DATA cssmCert = {certDataLen, (uint8 *)certData}; - OSStatus ortn = SecCertificateCreateFromData(&cssmCert, - CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, - &rtnCert); - if(ortn) { - cssmPerror("SecCertificateCreateFromData", ortn); - printf("***Error creating cert fromn %s. Aborting.\n", fileName); - } - free(certData); - return rtnCert; -} - -static int dumpCertFiles( - CFArrayRef allCerts, - const char *fileBase, - bool quiet) -{ - char fileName[200]; - - if(allCerts == NULL) { - printf("...no certs to write.\n"); - return 0; - } - CFIndex numCerts = CFArrayGetCount(allCerts); - if(numCerts == 0) { - printf("...no certs to write.\n"); - return 0; - } - for(CFIndex dex=0; dex=0) to verify - int numCertsVfy, // optionjal (>= 0) to verify - bool parseSignerCert, - const char *certFileBase, // optionally write certs here - bool customDecoder, // invoke CMSDecoderSetDecoder() - bool manTrustEval, // evaluate SecTrust ourself - CFMutableArrayRef anchorArray, // optional, and only for manTrustEval - bool quiet, - CFDataRef *outData) // RETURNED -{ - if((data == NULL) || (dataLen == 0)) { - fprintf(stderr, "***Parse requires input file. Aborting.\n"); - return paramErr; - } - - CMSDecoderRef cmsDecoder; - size_t numSigners; - Boolean isEncrypted; - CFArrayRef allCerts = NULL; - unsigned signerDex; - SecPolicyRef policy = NULL; - SecPolicySearchRef policySearch = NULL; - CFIndex numCerts = 0; - int addDetachedAfterDecode = 0; - SecArenaPoolRef arena = NULL; - - /* - * Four different return codes: - * -- ortn used for function returns; if nonzero, bail immediately and goto errOut - * -- ourRtn is manually set per the output of CMSDecoderCopySignerStatus and - * evalSecTrust - * -- trustRtn is the output of manual SecTrustEvaluate (via evalSecTrust()) - * -- vfyErr indicates mismatch in caller-specified error params - * - * All four have to be zero fgor us to return zero. - */ - OSStatus ourRtn = noErr; - OSStatus ortn = noErr; - OSStatus trustRtn = noErr; - int vfyErr = 0; - - ortn = CMSDecoderCreate(&cmsDecoder); - if(ortn) { - cssmPerror("CMSDecoderCreate", ortn); - return ortn; - } - - /* subsequent errors to errOut: */ - - if(detachedContent != NULL) { - /* - * We can add detached content either before or after the - * update/finalize; to test and verify, flip a coin to decide - * when to do it. - */ - addDetachedAfterDecode = genRand(0, 1); - if(!addDetachedAfterDecode) { - CFDataRef cfDetach = CFDataCreate(NULL, detachedContent, detachedContentLen); - ortn = CMSDecoderSetDetachedContent(cmsDecoder, cfDetach); - CFRelease(cfDetach); - if(ortn) { - cssmPerror("CMSDecoderSetDetachedContent", ortn); - goto errOut; - } - } - } - - if(customDecoder) { - /* Create a decoder; we don't have to free it, but we do have to free the - * arena pool */ - SecCmsDecoderRef coder = NULL; - - ortn = SecArenaPoolCreate(1024, &arena); - if(ortn) { - cssmPerror("SecArenaPoolCreate", ortn); - goto errOut; - } - ortn = SecCmsDecoderCreate(arena, - NULL, NULL, NULL, NULL, NULL, NULL, &coder); - if(ortn) { - cssmPerror("SecCmsDecoderCreate", ortn); - goto errOut; - } - ortn = CMSDecoderSetDecoder(cmsDecoder, coder); - if(ortn) { - cssmPerror("CMSDecoderSetDecoder", ortn); - goto errOut; - } - else if(!quiet) { - printf("...set up custom SecCmsDecoderRef\n"); - } - } - if(multiUpdate) { - ortn = updateDecoder(cmsDecoder, data, dataLen); - if(ortn) { - goto errOut; - } - } - else { - ortn = CMSDecoderUpdateMessage(cmsDecoder, data, dataLen); - if(ortn) { - cssmPerror("CMSDecoderUpdateMessage", ortn); - goto errOut; - } - } - ortn = CMSDecoderFinalizeMessage(cmsDecoder); - if(ortn) { - cssmPerror("CMSDecoderFinalizeMessage", ortn); - goto errOut; - } - if(addDetachedAfterDecode) { - CFDataRef cfDetach = CFDataCreate(NULL, detachedContent, detachedContentLen); - ortn = CMSDecoderSetDetachedContent(cmsDecoder, cfDetach); - CFRelease(cfDetach); - if(ortn) { - cssmPerror("CMSDecoderSetDetachedContent", ortn); - goto errOut; - } - } - ortn = CMSDecoderGetNumSigners(cmsDecoder, &numSigners); - if(ortn) { - cssmPerror("CMSDecoderGetNumSigners", ortn); - goto errOut; - } - ortn = CMSDecoderIsContentEncrypted(cmsDecoder, &isEncrypted); - if(ortn) { - cssmPerror("CMSDecoderIsContentEncrypted", ortn); - goto errOut; - } - ortn = CMSDecoderCopyAllCerts(cmsDecoder, &allCerts); - if(ortn) { - cssmPerror("CMSDecoderCopyAllCerts", ortn); - goto errOut; - } - if(allCerts) { - numCerts = CFArrayGetCount(allCerts); - } - - /* optional verify of expected message type */ - switch(vfyOp) { - case CTV_None: - break; - case CTV_Sign: - if((numSigners == 0) && (allCerts == NULL)) { - fprintf(stderr, "***Expected SignedData, but no signersFound\n"); - vfyErr = 1; - /* but keep going */ - } - if(isEncrypted) { - fprintf(stderr, "***Expected SignedData, but msg IS encrypted\n"); - vfyErr = 1; - } - break; - case CTV_SignEnvelop: - if(numSigners == 0) { - fprintf(stderr, "***Expected Signed&Enveloped, but no signersFound\n"); - vfyErr = 1; - } - if(!isEncrypted) { - fprintf(stderr, "***Expected Signed&Enveloped, but msg not encrypted\n"); - vfyErr = 1; - } - break; - case CTV_Envelop: - if(numSigners != 0) { - fprintf(stderr, "***Expected EnvelopedData, but signers found\n"); - vfyErr = 1; - } - if(!isEncrypted) { - fprintf(stderr, "***Expected EnvelopedData, but msg not encrypted\n"); - vfyErr = 1; - } - break; - } - - if(numSignersVfy >= 0) { - if((unsigned)numSignersVfy != numSigners) { - fprintf(stderr, "***Expected %d signers; found %lu\n", - numSignersVfy, numSigners); - vfyErr = 1; - } - } - if(numCertsVfy >= 0) { - if((int)numCerts != numCertsVfy) { - fprintf(stderr, "***Expected %d certs; found %d\n", - numCertsVfy, (int)numCerts); - vfyErr = 1; - } - } - if(!quiet) { - fprintf(stderr, "=== CMS message info ===\n"); - fprintf(stderr, " Num Signers : %lu\n", (unsigned long)numSigners); - fprintf(stderr, " Encrypted : %s\n", isEncrypted ? "true" : "false"); - fprintf(stderr, " Num Certs : %lu\n", - allCerts ? (unsigned long)CFArrayGetCount(allCerts) : 0); - } - - if((certFileBase != NULL) & (allCerts != NULL)) { - dumpCertFiles(allCerts, certFileBase, quiet); - } - - - if(numSigners) { - CSSM_OID eContentType = {0, NULL}; - CFDataRef eContentData = NULL; - OidParser oidParser; - char str[OID_PARSER_STRING_SIZE]; - - ortn = CMSDecoderCopyEncapsulatedContentType(cmsDecoder, &eContentData); - if(ortn) { - cssmPerror("CMSDecoderCopyEncapsulatedContentType", ortn); - goto errOut; - } - if(eContentData != NULL) { - eContentType.Data = (uint8 *)CFDataGetBytePtr(eContentData); - eContentType.Length = CFDataGetLength(eContentData); - } - if(!quiet) { - /* can't use stderr - oidparser is fixed w/stdout */ - printf(" eContentType : "); - if(eContentType.Data == NULL) { - printf("***NONE FOUND***\n"); - } - else if(eContentType.Length == 0) { - printf("***EMPTY***\n"); - } - else { - oidParser.oidParse(eContentType.Data, eContentType.Length, str); - printf("%s\n", str); - } - } - - if(eContentVfy != NULL) { - if(eContentType.Data == NULL) { - fprintf(stderr, "***Tried to verify eContentType, but none found\n"); - vfyErr = 1; - } - else if(!appCompareCssmData(eContentVfy, &eContentType)) { - fprintf(stderr, "***eContentType verify error\n"); - fprintf(stderr, " Expected: "); - oidParser.oidParse(eContentVfy->Data, eContentVfy->Length, str); - printf("%s\n", str); - fprintf(stderr, " Found : "); - oidParser.oidParse(eContentType.Data, eContentType.Length, str); - printf("%s\n", str); - vfyErr = 1; - } - } - CFRELEASE(eContentData); - - /* get a policy for cert evaluation */ - ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, - &CSSMOID_APPLE_X509_BASIC, - NULL, - &policySearch); - if(ortn) { - cssmPerror("SecPolicySearchCreate", ortn); - goto errOut; - } - ortn = SecPolicySearchCopyNext(policySearch, &policy); - if(ortn) { - cssmPerror("SecPolicySearchCopyNext", ortn); - goto errOut; - } - } - for(signerDex=0; signerDex>\n"); - } - else { - char emailStr[1000]; - if(!CFStringGetCString(signerEmailAddress, - emailStr, 1000, kCFStringEncodingASCII)) { - fprintf(stderr, "<<>>\n"); - } - else { - fprintf(stderr, "%s\n", emailStr); - } - } - - fprintf(stderr, " vfyResult : %s\n", - certVerifyResultCode ? - cssmErrToStr(certVerifyResultCode) : "Success"); - - /* TBD: optionally manually verify the SecTrust object */ - - if(parseSignerCert) { - - if(signerCert == NULL) { - fprintf(stderr, " <<>>\n"); - } - else { - CSSM_DATA certData; - ortn = SecCertificateGetData(signerCert, &certData); - if(ortn) { - fprintf(stderr, " <<>>\n"); - cssmPerror("SecCertificateGetData", ortn); - } - else { - printf("========== Signer Cert==========\n\n"); - printCert(certData.Data, certData.Length, CSSM_FALSE); - printf("========== End Signer Cert==========\n\n"); - } - } - } /* parseSignerCert */ - } /* displaying per-signer info */ - - CFRELEASE(signerCert); - signerCert = NULL; - CFRELEASE(signerEmailAddress); - signerEmailAddress = NULL; - CFRELEASE(secTrust); - secTrust = NULL; - } /* for signerDex */ - - if(ortn == noErr) { - ortn = CMSDecoderCopyContent(cmsDecoder, outData); - if(ortn) { - cssmPerror("CMSDecoderCopyContent", ortn); - } - } - -errOut: - CFRelease(cmsDecoder); - if(arena != NULL) { - SecArenaPoolFree(arena, false); - } - - CFRELEASE(allCerts); - CFRELEASE(policySearch); - CFRELEASE(policy); - if(ourRtn) { - return ourRtn; - } - else if(trustRtn) { - return trustRtn; - } - else if(vfyErr) { - return vfyErr; - } - else { - return ortn; - } -} - -static OSStatus doSign( - CFTypeRef signerOrArray, - const unsigned char *inData, - unsigned inDataLen, - bool multiUpdate, - bool detachedContent, - const CSSM_OID *eContentType, // OPTIONAL - CMSSignedAttributes attrs, - CFTypeRef otherCerts, // OPTIONAL - bool customCoder, - bool getCmsMsg, - CMSCertificateChainMode chainMode, - bool quiet, - CFDataRef *outData) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Sign requires input file. Aborting.\n"); - return paramErr; - } - if(signerOrArray == NULL) { - fprintf(stderr, "***Sign requires a signing identity. Aborting.\n"); - return paramErr; - } - - OSStatus ortn; - CMSEncoderRef cmsEncoder = NULL; - SecCmsMessageRef msg = NULL; /* for optional CMSEncoderGetCmsMessage */ - SecArenaPoolRef arena = NULL; - CSSM_DATA encoderOut = {0, NULL}; - - if(multiUpdate || otherCerts || getCmsMsg || customCoder || - (chainMode != kCMSCertificateChain)) { - /* one-shot encode doesn't support otherCerts or chainOptions*/ - - ortn = CMSEncoderCreate(&cmsEncoder); - if(ortn) { - cssmPerror("CMSEncoderCreate", ortn); - return ortn; - } - /* subsequent errors to errOut: */ - if(signerOrArray != NULL) { - ortn = CMSEncoderAddSigners(cmsEncoder, signerOrArray); - if(ortn) { - goto errOut; - } - } - if(eContentType) { - ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType); - if(ortn) { - goto errOut; - } - } - if(detachedContent) { - ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent); - if(ortn) { - goto errOut; - } - } - if(otherCerts) { - ortn = CMSEncoderAddSupportingCerts(cmsEncoder, otherCerts); - if(ortn) { - goto errOut; - } - } - if(attrs) { - ortn = CMSEncoderAddSignedAttributes(cmsEncoder, attrs); - if(ortn) { - goto errOut; - } - } - if(chainMode != kCMSCertificateChain) { - ortn = CMSEncoderSetCertificateChainMode(cmsEncoder, chainMode); - if(ortn) { - goto errOut; - } - } - if(getCmsMsg || customCoder) { - /* - * We just want to trigger the state transition - * that we know should happen. We also might need - * the msg to create a custom coder. - */ - ortn = CMSEncoderGetCmsMessage(cmsEncoder, &msg); - if(ortn) { - cssmPerror("CMSEncoderGetCmsMessage", ortn); - goto errOut; - } - } - - if(customCoder) { - SecCmsEncoderRef coder = NULL; - ortn = SecArenaPoolCreate(1024, &arena); - if(ortn) { - cssmPerror("SecArenaPoolCreate", ortn); - goto errOut; - } - ortn = SecCmsEncoderCreate(msg, - NULL, NULL, // no callback - &encoderOut, // data goes here - arena, - NULL, NULL, // no password callback (right?) - NULL, NULL, // decrypt key callback - NULL, NULL, // detached digests - &coder); - if(ortn) { - cssmPerror("SecCmsEncoderCreate", ortn); - goto errOut; - } - ortn = CMSEncoderSetEncoder(cmsEncoder, coder); - if(ortn) { - cssmPerror("CMSEncoderSetEncoder", ortn); - goto errOut; - } - else if(!quiet) { - printf("...set up custom SecCmsEncoderRef\n"); - } - } - /* random number of random-sized updates */ - ortn = updateEncoder(cmsEncoder, inData, inDataLen); - if(ortn) { - goto errOut; - } - - ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); - if(ortn) { - cssmPerror("CMSEncoderCopyEncodedContent", ortn); - } - if(customCoder) { - /* we have the data right here */ - *outData = CFDataCreate(NULL, - (const UInt8 *)encoderOut.Data, encoderOut.Length); - } - } - else { - ortn = CMSEncode(signerOrArray, - NULL, /* recipients */ - eContentType, - detachedContent, - attrs, - inData, inDataLen, - outData); - if(ortn) { - printf("***CMSEncode returned %ld\n", (long)ortn); - cssmPerror("CMSEncode", ortn); - } - } -errOut: - if(cmsEncoder) { - CFRelease(cmsEncoder); - } - if(arena) { - SecArenaPoolFree(arena, false); - } - return ortn; -} - -static OSStatus doEncrypt( - CFTypeRef recipOrArray, - const unsigned char *inData, - unsigned inDataLen, - bool multiUpdate, - CFDataRef *outData) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Encrypt requires input file. Aborting.\n"); - return paramErr; - } - if(recipOrArray == NULL) { - fprintf(stderr, "***Encrypt requires a recipient certificate. Aborting.\n"); - return paramErr; - } - - OSStatus ortn; - CMSEncoderRef cmsEncoder = NULL; - - if(multiUpdate) { - ortn = CMSEncoderCreate(&cmsEncoder); - if(ortn) { - cssmPerror("CMSEncoderCreate", ortn); - return ortn; - } - /* subsequent errors to errOut: */ - ortn = CMSEncoderAddRecipients(cmsEncoder, recipOrArray); - if(ortn) { - goto errOut; - } - - /* random number of random-sized updates */ - ortn = updateEncoder(cmsEncoder, inData, inDataLen); - if(ortn) { - goto errOut; - } - ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); - if(ortn) { - cssmPerror("CMSEncoderCopyEncodedContent", ortn); - } - } - else { - /* one-shot */ - ortn = CMSEncode(NULL, /* signers */ - recipOrArray, - NULL, /* eContentType */ - FALSE, /* detachedContent */ - kCMSAttrNone, - inData, inDataLen, - outData); - if(ortn) { - printf("***CMSEncode returned %ld\n", (long)ortn); - cssmPerror("CMSEncode", ortn); - } - } -errOut: - if(cmsEncoder) { - CFRelease(cmsEncoder); - } - return ortn; -} - -/* create nested message: msg = EnvelopedData(SignedData(inData)) */ -static OSStatus doSignEncrypt( - CFTypeRef recipOrArray, // encryption recipients - CFTypeRef signerOrArray, // signers - const CSSM_OID *eContentType, // OPTIONAL - for signedData - CMSSignedAttributes attrs, - const unsigned char *inData, - unsigned inDataLen, - bool multiUpdate, - CFTypeRef otherCerts, // OPTIONAL - CFDataRef *outData) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Sign/Encrypt requires input file. Aborting.\n"); - return paramErr; - } - if(recipOrArray == NULL) { - fprintf(stderr, "***Sign/Encrypt requires a recipient certificate. Aborting.\n"); - return paramErr; - } - if(signerOrArray == NULL) { - fprintf(stderr, "***Sign/Encrypt requires a signer Identity. Aborting.\n"); - return paramErr; - } - - OSStatus ortn; - CMSEncoderRef cmsEncoder = NULL; - - if(multiUpdate || otherCerts) { - ortn = CMSEncoderCreate(&cmsEncoder); - if(ortn) { - cssmPerror("CMSEncoderCreate", ortn); - return ortn; - } - /* subsequent errors to errOut: */ - ortn = CMSEncoderAddRecipients(cmsEncoder, recipOrArray); - if(ortn) { - goto errOut; - } - ortn = CMSEncoderAddSigners(cmsEncoder, signerOrArray); - if(ortn) { - goto errOut; - } - if(eContentType) { - ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType); - if(ortn) { - goto errOut; - } - } - if(otherCerts) { - ortn = CMSEncoderAddSupportingCerts(cmsEncoder, otherCerts); - if(ortn) { - goto errOut; - } - } - if(attrs) { - ortn = CMSEncoderAddSignedAttributes(cmsEncoder, attrs); - if(ortn) { - goto errOut; - } - } - - /* random number of random-sized updates */ - ortn = updateEncoder(cmsEncoder, inData, inDataLen); - if(ortn) { - goto errOut; - } - ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); - if(ortn) { - cssmPerror("CMSEncoderCopyEncodedContent", ortn); - } - } - else { - ortn = CMSEncode(signerOrArray, - recipOrArray, - eContentType, - FALSE, /* detachedContent */ - attrs, - inData, inDataLen, - outData); - if(ortn) { - printf("***CMSEncode returned %ld\n", (long)ortn); - cssmPerror("CMSEncode", ortn); - } - } - -errOut: - if(cmsEncoder) { - CFRelease(cmsEncoder); - } - return ortn; -} - -/* - * Create a CMS message containing only certs. - */ -static OSStatus makeCertBag( - CFTypeRef certsOrArray, - CFDataRef *outData) -{ - if(certsOrArray == NULL) { - printf("***Need some certs to generate this type of message.\n"); - return -1; - } - - OSStatus ortn; - CMSEncoderRef cmsEncoder = NULL; - - ortn = CMSEncoderCreate(&cmsEncoder); - if(ortn) { - cssmPerror("CMSEncoderCreate", ortn); - return ortn; - } - /* subsequent errors to errOut: */ - ortn = CMSEncoderAddSupportingCerts(cmsEncoder, certsOrArray); - if(ortn) { - goto errOut; - } - ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); - if(ortn) { - cssmPerror("CMSEncoderCopyEncodedContent", ortn); - } -errOut: - CFRelease(cmsEncoder); - return ortn; -} - -/* - * Support maintanance of single item or array of them. - * - * Given new incoming 'newThing': - * if both *thingArray and *currThing are NULL - * *currThing = newThing; - * done; - * create *thingArray; - * add *currThing to *thingArray if present; - * add newThing to *thingArray; - */ -static void addThing( - CFTypeRef newThing, - CFTypeRef *currThing, - CFMutableArrayRef *thingArray) -{ - if((*currThing == NULL) && (*thingArray == NULL)) { - /* first occurrence of a thing */ - *currThing = newThing; - return; - } - - /* at least two things - prepare array */ - if(*thingArray == NULL) { - *thingArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - } - if(*currThing != NULL) { - /* move current thing to array */ - CFArrayAppendValue(*thingArray, *currThing); - CFRelease(*currThing); - *currThing = NULL; - } - CFArrayAppendValue(*thingArray, newThing); - CFRelease(newThing); -} - -int main(int argc, char **argv) -{ - if(argc < 2) { - usage(argv); - } - - CT_Op op; - bool needId = false; - if(!strcmp(argv[1], "sign")) { - op = CTO_Sign; - needId = true; - } - else if(!strcmp(argv[1], "envel")) { - op = CTO_Envelop; - } - else if(!strcmp(argv[1], "signEnv")) { - op = CTO_SignEnvelop; - needId = true; - } - else if(!strcmp(argv[1], "certs")) { - op = CTO_CertsOnly; - } - else if(!strcmp(argv[1], "parse")) { - op = CTO_Parse; - } - else { - fprintf(stderr, "***Unrecognized cmd.\n"); - usage(argv); - } - - extern int optind; - extern char *optarg; - int arg; - OSStatus ortn; - - /* optional args */ - char *inFileName = NULL; - char *outFileName = NULL; - bool detachedContent = false; - char *detachedFile = NULL; - bool useIdPicker = false; - bool quiet = false; - bool silent = false; - bool parseSignerCert = false; - const CSSM_OID *eContentType = NULL; - bool multiUpdate = false; - bool loopPause = false; - char *certFileBase = NULL; - CMSSignedAttributes signedAttrs = 0; - char *anchorFile = NULL; - bool manTrustEval = false; - CMSCertificateChainMode chainMode = kCMSCertificateChain; - - /* for verification, usually in quiet/script mode */ - CT_Vfy vfyOp = CTV_None; - const CSSM_OID *eContentVfy = NULL; - int numSignersVfy = -1; - int numCertsVfy = -1; - - /* for verifying functions in CMSPrivate.h */ - bool customCoder = false; - bool fetchSecCmsMsg = false; - - /* - * Signer/recipient items and arrays - use one item if possible, - * else array (to test both paths) - */ - SecIdentityRef signerId = NULL; - CFMutableArrayRef signerArray = NULL; - SecCertificateRef recipCert = NULL; - CFMutableArrayRef recipArray = NULL; - SecCertificateRef generalCert = NULL; - CFMutableArrayRef generalCertArray = NULL; - SecKeychainRef kcRef = NULL; - CFMutableArrayRef anchorArray = NULL; - - optind = 2; - while ((arg = getopt(argc, argv, "i:o:k:pr:R:dD:e:mlqcv:s:E:S:C:f:N:a:A:M12t:Z")) != -1) { - switch (arg) { - case 'i': - inFileName = optarg; - break; - case 'o': - outFileName = optarg; - break; - case 'k': - kcRef = keychain_open(optarg); - if(!kcRef) { - // cssmPerror("SecKeychainOpen", ortn); - exit(1); - } - break; - case 'p': - useIdPicker = true; - break; - case 'r': - { - SecCertificateRef newCert = NULL; - char *recipient = optarg; - ortn = findCert(recipient, kcRef, &newCert); - if(ortn) { - exit(1); - } - addThing(newCert, (CFTypeRef *)&recipCert, &recipArray); - break; - } - case 'R': - { - SecCertificateRef certRef = readCertFile(optarg); - if(certRef == NULL) { - exit(1); - } - addThing(certRef, (CFTypeRef *)&recipCert, &recipArray); - break; - } - case 'S': - { - SecIdentityRef newId = NULL; - SecCertificateRef newCert = NULL; - char *signerEmail = optarg; - - /* - * first find the cert, optionally in the keychain already - * specified via -k - */ - ortn = findCert(signerEmail, kcRef, &newCert); - if(ortn) { - exit(1); - } - - /* map cert to an identity */ - ortn = SecIdentityCreateWithCertificate(kcRef, newCert, &newId); - if(ortn) { - cssmPerror("SecIdentityCreateWithCertificate", ortn); - exit(1); - } - - addThing(newId, (CFTypeRef *)&signerId, &signerArray); - CFRelease(newCert); - break; - } - case 'C': - { - SecCertificateRef newCert = readCertFile(optarg); - if(newCert == NULL) { - exit(1); - } - addThing(newCert, (CFTypeRef *)&generalCert, &generalCertArray); - break; - } - case 'c': - parseSignerCert = true; - break; - case 'v': - if(!strcmp(optarg, "sign")) { - vfyOp = CTV_Sign; - } - else if(!strcmp(optarg, "encr")) { - vfyOp = CTV_Envelop; - } - else if(!strcmp(optarg, "signEnv")) { - vfyOp = CTV_SignEnvelop; - } - else { - usage(argv); - } - break; - case 'e': - switch(optarg[0]) { - case 'a': - eContentType = &CSSMOID_PKINIT_AUTH_DATA; - break; - case 'r': - eContentType = &CSSMOID_PKINIT_RKEY_DATA; - break; - default: - usage(argv); - } - break; - case 'E': - switch(optarg[0]) { - case 'a': - eContentVfy = &CSSMOID_PKINIT_AUTH_DATA; - break; - case 'r': - eContentVfy = &CSSMOID_PKINIT_RKEY_DATA; - break; - case 'd': - eContentVfy = &CSSMOID_PKCS7_Data; - break; - default: - usage(argv); - } - break; - case 'd': - if(op != CTO_Sign) { - printf("-d only valid for op sign\n"); - exit(1); - } - detachedContent = true; - break; - case 'D': - if(op != CTO_Parse) { - printf("-D only valid for op sign\n"); - exit(1); - } - detachedFile = optarg; - break; - case 'l': - loopPause = true; - break; - case 'm': - multiUpdate = true; - break; - case 's': - numSignersVfy = atoi(optarg); - break; - case 'f': - certFileBase = optarg; - break; - case 'N': - numCertsVfy = atoi(optarg); - break; - case '1': - customCoder = true; - break; - case '2': - fetchSecCmsMsg = true; - break; - case 'a': - for(; *optarg; optarg++) { - switch(*optarg) { - case 'c': - signedAttrs |= kCMSAttrSmimeCapabilities; - break; - case 'e': - signedAttrs |= kCMSAttrSmimeEncryptionKeyPrefs; - break; - case 'E': - signedAttrs |= kCMSAttrSmimeMSEncryptionKeyPrefs; - break; - case 't': - signedAttrs |= kCMSAttrSigningTime; - break; - default: - usage(argv); - } - } - break; - case 'A': - anchorFile = optarg; - break; - case 'M': - manTrustEval = true; - break; - case 't': - if(!strcmp(optarg, "none")) { - chainMode = kCMSCertificateNone; - } - else if(!strcmp(optarg, "signer")) { - chainMode = kCMSCertificateSignerOnly; - } - else if(!strcmp(optarg, "chain")) { - chainMode = kCMSCertificateChain; - } - else if(!strcmp(optarg, "chainWithRoot")) { - chainMode = kCMSCertificateChainWithRoot; - } - else { - printf("***Bogus cert chain spec***\n"); - usage(argv); - } - break; - case 'q': - quiet = true; - break; - case 'Z': - quiet = true; - silent = true; - break; - default: - case '?': - usage(argv); - } - } - if(optind != argc) { - /* getopt does not return '?' */ - usage(argv); - } - - unsigned char *inData = NULL; - unsigned inDataLen = 0; - unsigned char *detachedData = NULL; - unsigned detachedDataLen = 0; - CFDataRef outData = NULL; - CFIndex byteCount = 0; - if(!silent) { - testStartBanner((char *)"newCmsTool", argc, argv); - } - - if(inFileName) { - if(readFile(inFileName, &inData, &inDataLen)) { - fprintf(stderr, "***Error reading infile %s. Aborting.\n", inFileName); - exit(1); - } - } - if(detachedFile) { - if(readFile(detachedFile, &detachedData, &detachedDataLen)) { - fprintf(stderr, "***Error reading detachedFile %s. Aborting.\n", detachedFile); - exit(1); - } - } - - /* signer IDs */ - if(useIdPicker) { - ortn = sslSimpleIdentPicker(kcRef, &signerId); - if(ortn) { - fprintf(stderr, "***Error obtaining identity via picker. Aborting.\n"); - exit(1); - } - } - if(anchorFile) { - SecCertificateRef secCert = readCertFile(anchorFile); - if(secCert == NULL) { - exit(1); - } - anchorArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(anchorArray, secCert); - CFRelease(secCert); - } - - /* - * In order for signed blobs to contain a full cert chain, and to find - * certs matching a specific recipient cert email address, the keychain - * containing intermediates must be in the user's keychain search list - * (or, alternatively, the intermedaite certs must be added manually). - * To alleviate the burden on test scripts, we'll ensure that an optionally - * specified keychain is in factin the search list when we sign a message - * here. - * Careful - make sure to ALWAYS restore the search list! - */ - CFArrayRef originalSearchList = NULL; - if(kcRef != NULL) { - ortn = SecKeychainCopySearchList(&originalSearchList); - if(ortn) { - cssmPerror("SecKeychainCopySearchList", ortn); - exit(1); - } - CFMutableArrayRef newList = CFArrayCreateMutableCopy( - NULL, 0, originalSearchList); - CFArrayAppendValue(newList, kcRef); - ortn = SecKeychainSetSearchList(newList); - if(ortn) { - cssmPerror("SecKeychainSetSearchList", ortn); - exit(1); - } - /* DO NOT EXIT WITHOUT RESTORING TO originalSearchList */ - } - do { - switch(op) { - case CTO_Sign: - ortn = doSign((signerArray != NULL) ? - (CFTypeRef)signerArray : (CFTypeRef)signerId, - inData, inDataLen, - multiUpdate, detachedContent, eContentType, signedAttrs, - (generalCertArray != NULL) ? - (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, - customCoder, fetchSecCmsMsg, chainMode, quiet, - &outData); - break; - case CTO_Envelop: - ortn = doEncrypt(recipArray ? - (CFTypeRef)recipArray : (CFTypeRef)recipCert, - inData, inDataLen, - multiUpdate, &outData); - break; - case CTO_SignEnvelop: - ortn = doSignEncrypt(recipArray ? - (CFTypeRef)recipArray : (CFTypeRef)recipCert, - signerArray ? - (CFTypeRef)signerArray : (CFTypeRef)signerId, - eContentType, signedAttrs, - inData, inDataLen, multiUpdate, - (generalCertArray != NULL) ? - (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, - &outData); - break; - case CTO_CertsOnly: - ortn = makeCertBag((generalCertArray != NULL) ? - (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, - &outData); - break; - case CTO_Parse: - ortn = doParse(inData, inDataLen, - detachedData, detachedDataLen, - multiUpdate, - vfyOp, eContentVfy, numSignersVfy, numCertsVfy, - parseSignerCert, certFileBase, customCoder, - manTrustEval, anchorArray, - quiet, &outData); - break; - } - - if(loopPause) { - if(outData) { - printf("...generated %u bytes of data.\n", - (unsigned)CFDataGetLength(outData)); - } - fpurge(stdin); - printf("q to quit, anything else to loop again: "); - char resp = getchar(); - if(resp == 'q') { - break; - } - else { - CFRELEASE(outData); - outData = NULL; - } - } - } while (loopPause); - - if(originalSearchList) { - ortn = SecKeychainSetSearchList(originalSearchList); - if(ortn) { - cssmPerror("SecKeychainSetSearchList", ortn); - /* keep going */ - } - } - - if(ortn) { - goto errOut; - } - - byteCount = outData ? CFDataGetLength(outData) : 0; - if(outData && outFileName) { - if(writeFile(outFileName, CFDataGetBytePtr(outData), byteCount)) { - fprintf(stderr, "***Error writing to %s.\n", outFileName); - ortn = -1; - } - else { - if(!quiet) { - fprintf(stderr, "...wrote %u bytes to %s.\n", - (unsigned)byteCount, outFileName); - } - } - } - else if(byteCount) { - fprintf(stderr, "...generated %u bytes but no place to write it.\n", - (unsigned)byteCount); - } - else if(outFileName) { - fprintf(stderr, "...nothing to write to file %s.\n", outFileName); - /* assume this is an error, caller wanted something */ - ortn = -1; - } -errOut: - return ortn; -} - -/* - From SecurityTool/keychain_utilites.cpp - This properly supports dynamic keychains, i.e. smartcards -*/ - -SecKeychainRef keychain_open(const char *name) -{ - SecKeychainRef keychain = NULL; - OSStatus result; - -// check_obsolete_keychain(name); - if (name && name[0] != '/') - { - CFArrayRef dynamic = NULL; - result = SecKeychainCopyDomainSearchList( - kSecPreferencesDomainDynamic, &dynamic); - if (result) - { - // cssmPerror("SecKeychainOpen", ortn); - // sec_error("SecKeychainCopyDomainSearchList %s: %s", - // name, sec_errstr(result)); - cssmPerror("SecKeychainCopyDomainSearchList", result); - return NULL; - } - else - { - uint32_t i; - uint32_t count = dynamic ? CFArrayGetCount(dynamic) : 0; - - for (i = 0; i < count; ++i) - { - char pathName[PATH_MAX]; - UInt32 ioPathLength = sizeof(pathName); - bzero(pathName, ioPathLength); - keychain = (SecKeychainRef)CFArrayGetValueAtIndex(dynamic, i); - result = SecKeychainGetPath(keychain, &ioPathLength, pathName); - if (result) - { - // sec_error("SecKeychainGetPath %s: %s", name, sec_errstr(result)); - cssmPerror("SecKeychainCopyDomainSearchList", result); - return NULL; - } - if (!strncmp(pathName, name, ioPathLength)) - { - CFRetain(keychain); - CFRelease(dynamic); - return keychain; - } - } - CFRelease(dynamic); - } - } - - result = SecKeychainOpen(name, &keychain); - if (result) - { - // sec_error("SecKeychainOpen %s: %s", name, sec_errstr(result)); - cssmPerror("SecKeychainOpen", result); - } - - return keychain; -} -