X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/SecurityTests/clxutils/cmstool/cmstool.cpp?ds=inline diff --git a/SecurityTests/clxutils/cmstool/cmstool.cpp b/SecurityTests/clxutils/cmstool/cmstool.cpp deleted file mode 100644 index ac24ef92..00000000 --- a/SecurityTests/clxutils/cmstool/cmstool.cpp +++ /dev/null @@ -1,1220 +0,0 @@ -/* - * cmstool.cpp - manipluate CMS messages, intended to be an alternate for the - * currently useless cms command in /usr/bin/security - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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(" parse -- parse a CMS message file\n"); - printf("Options:\n"); - printf(" -i infile\n"); - printf(" -o outfile\n"); - printf(" -k keychain -- Keychain to search for certs\n"); - printf(" -p -- Use identity picker\n"); - printf(" -r recipient -- specify recipient of enveloped data\n"); - printf(" -c -- parse signer cert\n"); - printf(" -v sign|encr -- verify message is signed/encrypted\n"); - printf(" -e eContentType -- a(uthData)|r(keyData)\n"); - printf(" -d detached -- infile contains detached content (sign only)\n"); - printf(" -D detachedContent -- detached content (parse only)\n"); - printf(" -q -- quiet\n"); - exit(1); -} - -/* high level op */ -typedef enum { - CTO_Sign, - CTO_Envelop, - CTO_SignEnvelop, - 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}; - -typedef struct { - CSSM_OID contentType; - CSSM_DATA content; -} SimpleContentInfo; - -const SecAsn1Template SimpleContentInfoTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SimpleContentInfo) }, - { SEC_ASN1_OBJECT_ID, offsetof(SimpleContentInfo, contentType) }, - { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(SimpleContentInfo, content), - kSecAsn1AnyTemplate }, - { 0, } -}; - -/* - * Obtain the content of a contentInfo, This basically strips off the contentType OID - * and returns a mallocd copy of the ASN_ANY content. - */ -static OSStatus ContentInfoContent( - const unsigned char *contentInfo, - unsigned contentInfoLen, - unsigned char **content, /* mallocd and RETURNED */ - unsigned *contentLen) /* RETURNED */ -{ - SecAsn1CoderRef coder = NULL; - OSStatus ortn; - SimpleContentInfo decodedInfo; - - ortn = SecAsn1CoderCreate(&coder); - if(ortn) { - return ortn; - } - memset(&decodedInfo, 0, sizeof(decodedInfo)); - ortn = SecAsn1Decode(coder, contentInfo, contentInfoLen, - SimpleContentInfoTemplate, &decodedInfo); - if(ortn) { - goto errOut; - } - if(decodedInfo.content.Data == NULL) { - printf("***Error decoding contentInfo: no content\n"); - ortn = internalComponentErr; - goto errOut; - } - *content = (unsigned char *)malloc(decodedInfo.content.Length); - memmove(*content, decodedInfo.content.Data, decodedInfo.content.Length); - *contentLen = decodedInfo.content.Length; -errOut: - SecAsn1CoderRelease(coder); - return ortn; -} - -/* - * Find a cert in specified keychain or keychain list matching specified - * email address. We happen to knopw that the email address is stored with the - * kSecKeyAlias 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 = kSecKeyAlias; - 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 founmd matching recipient %s. Aborting.\n", - emailAddress); - return ortn; - } - CFRelease(srch); - return noErr; -} - -static void evalSecTrust( - SecTrustRef secTrust, - bool quiet) -{ - OSStatus ortn; - SecTrustResultType secTrustResult; - - ortn = SecTrustEvaluate(secTrust, &secTrustResult); - if(ortn) { - /* should never happen */ - cssmPerror("SecTrustEvaluate", ortn); - return; - } - switch(secTrustResult) { - case kSecTrustResultUnspecified: - /* cert chain valid, no special UserTrust assignments */ - case kSecTrustResultProceed: - /* cert chain valid AND user explicitly trusts this */ - if(!quiet) { - fprintf(stderr, "Successful\n"); - } - return; - case kSecTrustResultDeny: - case kSecTrustResultConfirm: - /* - * Cert chain may well have verified OK, but user has flagged - * one of these certs as untrustable. - */ - printf("Not trusted per user-specified Trust level\n"); - return; - default: - { - /* get low-level TP error */ - OSStatus tpStatus; - ortn = SecTrustGetCssmResultCode(secTrust, &tpStatus); - if(ortn) { - cssmPerror("SecTrustGetCssmResultCode", ortn); - return; - } - switch(tpStatus) { - case CSSMERR_TP_INVALID_ANCHOR_CERT: - fprintf(stderr, "Untrusted root\n"); - return; - case CSSMERR_TP_NOT_TRUSTED: - /* no root, not even in implicit SSL roots */ - fprintf(stderr, "No root cert found\n"); - return; - case CSSMERR_TP_CERT_EXPIRED: - fprintf(stderr, "Expired cert\n"); - return; - case CSSMERR_TP_CERT_NOT_VALID_YET: - fprintf(stderr, "Cert not valid yet\n"); - break; - default: - printf("Other cert failure: "); - cssmPerror("", tpStatus); - return; - } - } - } /* SecTrustEvaluate error */ - -} -static OSStatus parseSignedData( - SecCmsSignedDataRef signedData, - SecArenaPoolRef arena, /* used for detached content only */ - const unsigned char *detachedData, - unsigned detachedDataLen, - CT_Vfy vfyOp, - bool quiet, - bool parseSignerCert) -{ - Boolean b; - b = SecCmsSignedDataHasDigests(signedData); - if(!quiet) { - printf(" has digests : %s\n", b ? "true" : "false"); - } - - SecTrustRef secTrust = NULL; - OSStatus ortn; - SecPolicyRef policy = NULL; - SecPolicySearchRef policySearch = NULL; - - ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, - &CSSMOID_APPLE_X509_BASIC, - NULL, - &policySearch); - if(ortn) { - cssmPerror("SecPolicySearchCreate", ortn); - return ortn; - } - ortn = SecPolicySearchCopyNext(policySearch, &policy); - if(ortn) { - cssmPerror("SecPolicySearchCopyNext", ortn); - return ortn; - } - - int numSigners = SecCmsSignedDataSignerInfoCount(signedData); - if(!quiet) { - printf(" num signers : %d\n", numSigners); - } - for(int dex=0; dex "); - /* FIXME - does this make sense? Error? */ - } - } - else if(detachedData != NULL) { - /* digest the detached content */ - SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(signedData); - SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms); - CSSM_DATA **digests = NULL; - - SecCmsDigestContextUpdate(digcx, detachedData, detachedDataLen); - ortn = SecCmsDigestContextFinishMultiple(digcx, arena, &digests); - if(ortn) { - fprintf(stderr, "SecCmsDigestContextFinishMultiple() returned %d\n", (int)ortn); - } - else { - SecCmsSignedDataSetDigests(signedData, digestAlgorithms, digests); - } - } - else { - fprintf(stderr, " "); - } - ortn = SecCmsSignedDataVerifySignerInfo(signedData, dex, NULL, - policy, &secTrust); - if(ortn) { - fprintf(stderr, "vfSignerInfo() returned %d\n", (int)ortn); - fprintf(stderr, " vfy status : "); - } - if(secTrust == NULL) { - fprintf(stderr, "***NO SecTrust available!\n"); - } - else { - evalSecTrust(secTrust, quiet); - } - - SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, dex); - CFStringRef emailAddrs = SecCmsSignerInfoGetSignerCommonName(signerInfo); - char emailStr[1000]; - if(!quiet) { - fprintf(stderr, " signer : "); - } - if(emailAddrs == NULL) { - fprintf(stderr, "<>\n"); - } - else { - if(!CFStringGetCString(emailAddrs, emailStr, 1000, kCFStringEncodingASCII)) { - fprintf(stderr, "*** Error converting email address to C string\n"); - } - else if(!quiet) { - - fprintf(stderr, "%s\n", emailStr); - } - } - if(parseSignerCert) { - SecCertificateRef signer; - signer = SecCmsSignerInfoGetSigningCertificate(signerInfo, NULL); - if(signer) { - CSSM_DATA certData; - ortn = SecCertificateGetData(signer, &certData); - if(ortn) { - fprintf(stderr, "***Error getting signing cert data***\n"); - cssmPerror("SecCertificateGetData", ortn); - } - else { - printf("========== Signer Cert==========\n\n"); - printCert(certData.Data, certData.Length, CSSM_FALSE); - printf("========== End Signer Cert==========\n\n"); - } - } - else { - fprintf(stderr, "***Error getting signing cert ***\n"); - } - } - } - return ortn; -} - -static OSStatus doParse( - const unsigned char *data, - unsigned dataLen, - const unsigned char *detachedData, - unsigned detachedDataLen, - CT_Vfy vfyOp, - bool parseSignerCert, - bool quiet, - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - if((data == NULL) || (dataLen == 0)) { - fprintf(stderr, "***Parse requires input file. Aborting.\n"); - return paramErr; - } - - SecArenaPoolRef arena = NULL; - SecArenaPoolCreate(1024, &arena); - SecCmsMessageRef cmsMsg = NULL; - SecCmsDecoderRef decoder; - OSStatus ortn; - OSStatus ourRtn = noErr; - bool foundOneSigned = false; - bool foundOneEnveloped = false; - - ortn = SecCmsDecoderCreate(arena, NULL, NULL, NULL, NULL, NULL, NULL, &decoder); - if(ortn) { - cssmPerror("SecCmsDecoderCreate", ortn); - return ortn; - } - ortn = SecCmsDecoderUpdate(decoder, data, dataLen); - if(ortn) { - cssmPerror("SecCmsDecoderUpdate", ortn); - return ortn; - } - ortn = SecCmsDecoderFinish(decoder, &cmsMsg); - if(ortn) { - cssmPerror("SecCmsDecoderFinish", ortn); - return ortn; - } - - Boolean b = SecCmsMessageIsSigned(cmsMsg); - switch(vfyOp) { - case CTV_None: - break; - case CTV_Sign: - if(!b) { - fprintf(stderr, "***Expected SignedData, but !SecCmsMessageIsSigned()\n"); - ourRtn = -1; - } - break; - case CTV_SignEnvelop: - if(!b) { - fprintf(stderr, "***Expected Signed&Enveloped, but !SecCmsMessageIsSigned()\n"); - ourRtn = -1; - } - break; - case CTV_Envelop: - if(b) { - fprintf(stderr, "***Expected EnvelopedData, but SecCmsMessageIsSigned() " - "TRUE\n"); - ourRtn = -1; - } - break; - } - int numContentInfos = SecCmsMessageContentLevelCount(cmsMsg); - if(!quiet) { - fprintf(stderr, "=== CMS message info ===\n"); - fprintf(stderr, " Signed : %s\n", b ? "true" : "false"); - b = SecCmsMessageIsEncrypted(cmsMsg); - fprintf(stderr, " Encrypted : %s\n", b ? "true" : "false"); - b = SecCmsMessageContainsCertsOrCrls(cmsMsg); - fprintf(stderr, " certs/crls : %s\n", b ? "present" : "not present"); - fprintf(stderr, " Num ContentInfos : %d\n", numContentInfos); - } - - /* FIXME needs work for CTV_SignEnvelop */ - OidParser oidParser; - for(int dex=0; dexLength == 0) { - printf("***EMPTY***\n"); - } - else { - char str[OID_PARSER_STRING_SIZE]; - oidParser.oidParse(typeOid->Data, typeOid->Length, str); - printf("%s\n", str); - } - } - SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); - switch(tag) { - case SEC_OID_PKCS7_SIGNED_DATA: - { - switch(vfyOp) { - case CTV_None: // caller doesn't care - case CTV_Sign: // got what we wanted - break; - case CTV_Envelop: - fprintf(stderr, "***Expected EnvelopedData, got SignedData\n"); - ourRtn = -1; - break; - case CTV_SignEnvelop: - printf("CTV_SignEnvelop code on demand\n"); - break; - } - foundOneSigned = true; - SecCmsSignedDataRef sd = - (SecCmsSignedDataRef) SecCmsContentInfoGetContent(ci); - parseSignedData(sd, arena, - detachedData, detachedDataLen, - vfyOp, quiet, parseSignerCert); - break; - } - case SEC_OID_PKCS7_DATA: - case SEC_OID_OTHER: - break; - case SEC_OID_PKCS7_ENVELOPED_DATA: - foundOneEnveloped = true; - if(vfyOp == CTV_Sign) { - fprintf(stderr, "***Expected SignedData, EnvelopedData\n"); - ourRtn = -1; - break; - } - case SEC_OID_PKCS7_ENCRYPTED_DATA: - switch(vfyOp) { - case CTV_None: - break; - case CTV_Sign: - fprintf(stderr, "***Expected SignedData, got EncryptedData\n"); - ourRtn = -1; - break; - case CTV_Envelop: - fprintf(stderr, "***Expected EnvelopedData, got EncryptedData\n"); - ourRtn = -1; - break; - case CTV_SignEnvelop: - printf("CTV_SignEnvelop code on demand\n"); - break; - } - break; - default: - fprintf(stderr, " other content type TBD\n"); - } - } - if(outData) { - CSSM_DATA_PTR odata = SecCmsMessageGetContent(cmsMsg); - if(odata == NULL) { - fprintf(stderr, "***No inner content available\n"); - } - else { - *outData = (unsigned char *)malloc(odata->Length); - memmove(*outData, odata->Data, odata->Length); - *outDataLen = odata->Length; - } - } - if(arena) { - SecArenaPoolFree(arena, false); - } - switch(vfyOp) { - case CTV_None: - break; - case CTV_Sign: - if(!foundOneSigned) { - fprintf(stderr, "Expected signed, never saw a SignedData\n"); - ourRtn = -1; - } - break; - case CTV_Envelop: - if(!foundOneEnveloped) { - fprintf(stderr, "Expected enveloped, never saw an EnvelopedData\n"); - ourRtn = -1; - } - break; - case CTV_SignEnvelop: - if(!foundOneSigned) { - fprintf(stderr, "Expected signed, never saw a SignedData\n"); - ourRtn = -1; - } - if(!foundOneEnveloped) { - fprintf(stderr, "Expected enveloped, never saw an EnvelopedData\n"); - ourRtn = -1; - } - break; - } - /* free decoder? cmsMsg? */ - return ourRtn; -} - -/* - * Common encode routine. - */ -#if 1 -/* the simple way, when 3655861 is fixed */ -static OSStatus encodeCms( - SecCmsMessageRef cmsMsg, - const unsigned char *inData, // add in this - unsigned inDataLen, - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - SecArenaPoolRef arena = NULL; - SecArenaPoolCreate(1024, &arena); - CSSM_DATA cdataIn = {inDataLen, (uint8 *)inData}; - CSSM_DATA cdataOut = {0, NULL}; - - OSStatus ortn = SecCmsMessageEncode(cmsMsg, &cdataIn, arena, &cdataOut); - if((ortn == noErr) && (cdataOut.Length != 0)) { - *outData = (unsigned char *)malloc(cdataOut.Length); - memmove(*outData, cdataOut.Data, cdataOut.Length); - *outDataLen = cdataOut.Length; - } - else { - cssmPerror("SecCmsMessageEncode", ortn); - *outData = NULL; - *outDataLen = 0; - } - SecArenaPoolFree(arena, false); - return ortn; -} - -#else - -/* the hard way back when SecCmsMessageEncode() didn't work */ -static OSStatus encodeCms( - SecCmsMessageRef cmsMsg, - const unsigned char *inData, // add in this - unsigned inDataLen, - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - SecArenaPoolRef arena = NULL; - SecArenaPoolCreate(1024, &arena); - SecCmsEncoderRef cmsEnc = NULL; - CSSM_DATA output = { 0, NULL }; - OSStatus ortn; - - ortn = SecCmsEncoderCreate(cmsMsg, - NULL, NULL, // no callback - &output, arena, // data goes here - NULL, NULL, // no password callback (right?) - NULL, NULL, // decrypt key callback - NULL, NULL, // detached digests - &cmsEnc); - if(ortn) { - cssmPerror("SecKeychainItemCopyKeychain", ortn); - goto errOut; - } - ortn = SecCmsEncoderUpdate(cmsEnc, (char *)inData, inDataLen); - if(ortn) { - cssmPerror("SecCmsEncoderUpdate", ortn); - goto errOut; - } - ortn = SecCmsEncoderFinish(cmsEnc); - if(ortn) { - cssmPerror("SecCMsEncoderFinish", ortn); - goto errOut; - } - - /* Did we get any data? */ - if(output.Length) { - *outData = (unsigned char *)malloc(output.Length); - memmove(*outData, output.Data, output.Length); - *outDataLen = output.Length; - } - else { - *outData = NULL; - *outDataLen = 0; - } -errOut: - if(arena) { - SecArenaPoolFree(arena, false); - } - return ortn; -} - -#endif - -static OSStatus doSign( - SecIdentityRef signerId, - const unsigned char *inData, - unsigned inDataLen, - bool detachedContent, - const CSSM_OID *eContentType, // OPTIONAL - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Sign requires input file. Aborting.\n"); - return paramErr; - } - if(signerId == NULL) { - fprintf(stderr, "***Sign requires a signing identity. Aborting.\n"); - return paramErr; - } - - SecCmsMessageRef cmsMsg = NULL; - SecCmsContentInfoRef contentInfo = NULL; - SecCmsSignedDataRef signedData = NULL; - SecCertificateRef ourCert = NULL; - SecCmsSignerInfoRef signerInfo; - OSStatus ortn; - SecKeychainRef ourKc = NULL; - - ortn = SecIdentityCopyCertificate(signerId, &ourCert); - if(ortn) { - cssmPerror("SecIdentityCopyCertificate", ortn); - return ortn; - } - ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)ourCert, &ourKc); - if(ortn) { - cssmPerror("SecKeychainItemCopyKeychain", ortn); - goto errOut; - } - - // build chain of objects: message->signedData->data - cmsMsg = SecCmsMessageCreate(NULL); - if(cmsMsg == NULL) { - fprintf(stderr, "***Error creating SecCmsMessageRef\n"); - ortn = -1; - goto errOut; - } - signedData = SecCmsSignedDataCreate(cmsMsg); - if(signedData == NULL) { - printf("***Error creating SecCmsSignedDataRef\n"); - ortn = -1; - goto errOut; - } - contentInfo = SecCmsMessageGetContentInfo(cmsMsg); - ortn = SecCmsContentInfoSetContentSignedData(cmsMsg, contentInfo, signedData); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentSignedData", ortn); - goto errOut; - } - contentInfo = SecCmsSignedDataGetContentInfo(signedData); - if(eContentType != NULL) { - ortn = SecCmsContentInfoSetContentOther(cmsMsg, contentInfo, - NULL /* data */, - detachedContent, - eContentType); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentData", ortn); - goto errOut; - } - } - else { - ortn = SecCmsContentInfoSetContentData(cmsMsg, contentInfo, NULL /* data */, - detachedContent); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentData", ortn); - goto errOut; - } - } - - /* - * create & attach signer information - */ - signerInfo = SecCmsSignerInfoCreate(cmsMsg, signerId, SEC_OID_SHA1); - if (signerInfo == NULL) { - fprintf(stderr, "***Error on SecCmsSignerInfoCreate\n"); - ortn = -1; - goto errOut; - } - /* we want the cert chain included for this one */ - /* FIXME - what's the significance of the usage? */ - ortn = SecCmsSignerInfoIncludeCerts(signerInfo, SecCmsCMCertChain, certUsageEmailSigner); - if(ortn) { - cssmPerror("SecCmsSignerInfoIncludeCerts", ortn); - goto errOut; - } - - /* other options go here - signing time, etc. */ - - ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, ourKc); - if(ortn) { - cssmPerror("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn); - goto errOut; - } - ortn = SecCmsSignedDataAddCertificate(signedData, ourCert); - if(ortn) { - cssmPerror("SecCmsSignedDataAddCertificate", ortn); - goto errOut; - } - - ortn = SecCmsSignedDataAddSignerInfo(signedData, signerInfo); - if(ortn) { - cssmPerror("SecCmsSignedDataAddSignerInfo", ortn); - goto errOut; - } - - /* go */ - ortn = encodeCms(cmsMsg, inData, inDataLen, outData, outDataLen); -errOut: - /* free resources */ - if(cmsMsg) { - SecCmsMessageDestroy(cmsMsg); - } - if(ourCert) { - CFRelease(ourCert); - } - if(ourKc) { - CFRelease(ourKc); - } - return ortn; -} - -static OSStatus doEncrypt( - SecCertificateRef recipCert, // eventually more than one - const unsigned char *inData, - unsigned inDataLen, - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Encrypt requires input file. Aborting.\n"); - return paramErr; - } - if(recipCert == NULL) { - fprintf(stderr, "***Encrypt requires a recipient certificate. Aborting.\n"); - return paramErr; - } - - SecCmsMessageRef cmsMsg = NULL; - SecCmsContentInfoRef contentInfo = NULL; - SecCmsEnvelopedDataRef envelopedData = NULL; - SecCmsRecipientInfoRef recipientInfo = NULL; - OSStatus ortn; - SecCertificateRef allCerts[2] = { recipCert, NULL}; - - SECOidTag algorithmTag; - int keySize; - - ortn = SecSMIMEFindBulkAlgForRecipients(allCerts, &algorithmTag, &keySize); - if(ortn) { - cssmPerror("SecSMIMEFindBulkAlgForRecipients", ortn); - return ortn; - } - - // build chain of objects: message->envelopedData->data - cmsMsg = SecCmsMessageCreate(NULL); - if(cmsMsg == NULL) { - fprintf(stderr, "***Error creating SecCmsMessageRef\n"); - ortn = -1; - goto errOut; - } - envelopedData = SecCmsEnvelopedDataCreate(cmsMsg, algorithmTag, keySize); - if(envelopedData == NULL) { - fprintf(stderr, "***Error creating SecCmsEnvelopedDataRef\n"); - ortn = -1; - goto errOut; - } - contentInfo = SecCmsMessageGetContentInfo(cmsMsg); - ortn = SecCmsContentInfoSetContentEnvelopedData(cmsMsg, contentInfo, envelopedData); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentEnvelopedData", ortn); - goto errOut; - } - contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData); - ortn = SecCmsContentInfoSetContentData(cmsMsg, contentInfo, NULL /* data */, false); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentData", ortn); - goto errOut; - } - - /* - * create & attach recipient information - */ - recipientInfo = SecCmsRecipientInfoCreate(cmsMsg, recipCert); - ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo); - if(ortn) { - cssmPerror("SecCmsEnvelopedDataAddRecipient", ortn); - goto errOut; - } - - - /* go */ - ortn = encodeCms(cmsMsg, inData, inDataLen, outData, outDataLen); -errOut: - /* free resources */ - if(cmsMsg) { - SecCmsMessageDestroy(cmsMsg); - } - return ortn; -} - -/* create nested message: msg = EnvelopedData(SignedData(inData)) */ -static OSStatus doSignEncrypt( - SecCertificateRef recipCert, // encryption recipient - SecIdentityRef signerId, // signer - const CSSM_OID *eContentType, // OPTIONAL - for signedData - const unsigned char *inData, - unsigned inDataLen, - unsigned char **outData, // mallocd and RETURNED - unsigned *outDataLen) // RETURNED -{ - if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { - fprintf(stderr, "***Sign/Encrypt requires input file. Aborting.\n"); - return paramErr; - } - if(recipCert == NULL) { - fprintf(stderr, "***Sign/Encrypt requires a recipient certificate. Aborting.\n"); - return paramErr; - } - if(signerId == NULL) { - fprintf(stderr, "***Sign/Encrypt requires a signer Identity. Aborting.\n"); - return paramErr; - } - - OSStatus ortn; - unsigned char *signedData = NULL; - unsigned signedDataLen = 0; - SecCmsMessageRef cmsMsg = NULL; - SecCmsContentInfoRef contentInfo = NULL; - SecCmsEnvelopedDataRef envelopedData = NULL; - SecCmsRecipientInfoRef recipientInfo = NULL; - SecCertificateRef allCerts[2] = { recipCert, NULL}; - SECOidTag algorithmTag; - int keySize; - - /* first get a SignedData */ - ortn = doSign(signerId, inData, inDataLen, - false, /* can't do detached content here */ - eContentType, - &signedData, &signedDataLen); - if(ortn) { - printf("***Error generating inner signedData. Aborting.\n"); - return ortn; - } - - /* extract just the content - don't need the whole ContentINfo */ - unsigned char *signedDataContent = NULL; - unsigned signedDataContentLen = 0; - ortn = ContentInfoContent(signedData, signedDataLen, &signedDataContent, &signedDataContentLen); - if(ortn) { - goto errOut; - } - - /* now wrap that in an EnvelopedData */ - ortn = SecSMIMEFindBulkAlgForRecipients(allCerts, &algorithmTag, &keySize); - if(ortn) { - cssmPerror("SecSMIMEFindBulkAlgForRecipients", ortn); - return ortn; - } - - // build chain of objects: message->envelopedData->data - cmsMsg = SecCmsMessageCreate(NULL); - if(cmsMsg == NULL) { - fprintf(stderr, "***Error creating SecCmsMessageRef\n"); - ortn = -1; - goto errOut; - } - envelopedData = SecCmsEnvelopedDataCreate(cmsMsg, algorithmTag, keySize); - if(envelopedData == NULL) { - fprintf(stderr, "***Error creating SecCmsEnvelopedDataRef\n"); - ortn = -1; - goto errOut; - } - contentInfo = SecCmsMessageGetContentInfo(cmsMsg); - ortn = SecCmsContentInfoSetContentEnvelopedData(cmsMsg, contentInfo, envelopedData); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentEnvelopedData", ortn); - goto errOut; - } - contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData); - - /* here's the difference: we override the 'data' content with a SignedData type, - * but we fool the smime lib into thinking it's a plain old data so it doesn't try - * to encode the SignedData */ - ortn = SecCmsContentInfoSetContentOther(cmsMsg, contentInfo, - NULL /* data */, - false, - &CSSMOID_PKCS7_SignedData); - if(ortn) { - cssmPerror("SecCmsContentInfoSetContentData", ortn); - goto errOut; - } - - /* - * create & attach recipient information - */ - recipientInfo = SecCmsRecipientInfoCreate(cmsMsg, recipCert); - ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo); - if(ortn) { - cssmPerror("SecCmsEnvelopedDataAddRecipient", ortn); - goto errOut; - } - - - /* go */ - ortn = encodeCms(cmsMsg, signedDataContent, signedDataContentLen, outData, outDataLen); -errOut: - /* free resources */ - if(cmsMsg) { - SecCmsMessageDestroy(cmsMsg); - } - if(signedData) { - free(signedData); - } - if(signedDataContent) { - free(signedDataContent); - } - return ortn; -} - -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], "parse")) { - op = CTO_Parse; - } - else { - fprintf(stderr, "***Unrecognized cmd.\n"); - usage(argv); - } - - extern int optind; - extern char *optarg; - int arg; - - /* optional args */ - const char *keychainName = NULL; - char *inFileName = NULL; - char *outFileName = NULL; - bool detachedContent = false; - char *detachedFile = NULL; - bool useIdPicker = false; - char *recipient = NULL; - bool quiet = false; - bool parseSignerCert = false; - CT_Vfy vfyOp = CTV_None; - const CSSM_OID *eContentType = NULL; - - optind = 2; - while ((arg = getopt(argc, argv, "i:o:k:pr:e:dD:qcv:")) != -1) { - switch (arg) { - case 'i': - inFileName = optarg; - break; - case 'o': - outFileName = optarg; - break; - case 'k': - keychainName = optarg; - break; - case 'p': - useIdPicker = true; - break; - case 'r': - recipient = optarg; - 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 '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 'q': - quiet = true; - break; - default: - case '?': - usage(argv); - } - } - if(optind != argc) { - /* getopt does not return '?' */ - usage(argv); - } - - SecIdentityRef idRef = NULL; - SecKeychainRef kcRef = NULL; - SecCertificateRef recipientCert = NULL; - unsigned char *inData = NULL; - unsigned inDataLen = 0; - unsigned char *outData = NULL; - unsigned outDataLen = 0; - unsigned char *detachedData = NULL; - unsigned detachedDataLen = 0; - OSStatus ortn; - - 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); - } - } - if(keychainName) { - ortn = SecKeychainOpen(keychainName, &kcRef); - if(ortn) { - cssmPerror("SecKeychainOpen", ortn); - exit(1); - } - } - if(useIdPicker) { - ortn = sslSimpleIdentPicker(kcRef, &idRef); - if(ortn) { - fprintf(stderr, "***Error obtaining identity via picker. Aborting.\n"); - exit(1); - } - } - else if(needId) { - /* use first identity in specified keychain */ - CFArrayRef array = sslKcRefToCertArray(kcRef, CSSM_FALSE, CSSM_FALSE, - NULL, // no verify policy - NULL); - if(array == NULL) { - fprintf(stderr, "***Error finding a signing cert. Aborting.\n"); - exit(1); - } - idRef = (SecIdentityRef)CFArrayGetValueAtIndex(array, 0); - if(idRef == NULL) { - fprintf(stderr, "***No identities found. Aborting.\n"); - exit(1); - } - CFRetain(idRef); - CFRelease(array); - } - if(recipient) { - ortn = findCert(recipient, kcRef, &recipientCert); - if(ortn) { - exit(1); - } - } - - switch(op) { - case CTO_Sign: - ortn = doSign(idRef, inData, inDataLen, - detachedContent, eContentType, - &outData, &outDataLen); - break; - case CTO_Envelop: - if(recipientCert == NULL) { - if(idRef == NULL) { - printf("***Need a recipient or an identity to encrypt\n"); - exit(1); - } - ortn = SecIdentityCopyCertificate(idRef, &recipientCert); - if(ortn) { - cssmPerror("SecIdentityCopyCertificate", ortn); - exit(1); - } - } - ortn = doEncrypt(recipientCert, inData, inDataLen, &outData, &outDataLen); - break; - case CTO_SignEnvelop: - ortn = doSignEncrypt(recipientCert, idRef, eContentType, - inData, inDataLen, &outData, &outDataLen); - break; - case CTO_Parse: - ortn = doParse(inData, inDataLen, - detachedData, detachedDataLen, - vfyOp, parseSignerCert, quiet, - &outData, &outDataLen); - break; - } - if(ortn) { - goto errOut; - } - if(outData && outFileName) { - if(writeFile(outFileName, outData, outDataLen)) { - fprintf(stderr, "***Error writing to %s.\n", outFileName); - ortn = -1; - } - else { - if(!quiet) { - fprintf(stderr, "...wrote %u bytes to %s.\n", outDataLen, outFileName); - } - } - } - else if(outData) { - fprintf(stderr, "...generated %u bytes but no place to write it.\n", outDataLen); - } - 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; -}