+++ /dev/null
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * Modifications Copyright (c) 2003-2009,2012,2014 Apple Inc. All Rights Reserved.
- *
- * cmsutil -- A command to work with CMS data
- */
-
-#include "security_tool.h"
-#include "keychain_utilities.h"
-#include "identity_find.h"
-
-#include <Security/SecCmsBase.h>
-#include <Security/SecCmsContentInfo.h>
-#include <Security/SecCmsDecoder.h>
-#include <Security/SecCmsDigestContext.h>
-#include <Security/SecCmsDigestedData.h>
-#include <Security/SecCmsEncoder.h>
-#include <Security/SecCmsEncryptedData.h>
-#include <Security/SecCmsEnvelopedData.h>
-#include <Security/SecCmsMessage.h>
-#include <Security/SecCmsRecipientInfo.h>
-#include <Security/SecCmsSignedData.h>
-#include <Security/SecCmsSignerInfo.h>
-#include <Security/SecSMIME.h>
-#include <Security/tsaSupport.h>
-
-#include <Security/oidsalg.h>
-#include <Security/SecPolicy.h>
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainSearch.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecIdentitySearch.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <utilities/SecCFRelease.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "cmsutil.h"
-
-// SecPolicyCopy
-#include <Security/SecPolicyPriv.h>
-// SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindBySubjectKeyID, SecCertificateFindByEmail
-#include <Security/SecCertificatePriv.h>
-// SecIdentitySearchCreateWithPolicy
-#include <Security/SecIdentitySearchPriv.h>
-
-#define SEC_CHECK0(CALL, ERROR) do { if (!(CALL)) { sec_error(ERROR); goto loser; } } while(0)
-#define SEC_CHECK(CALL, ERROR) do { rv = (CALL); if (rv) { sec_perror(ERROR, rv); goto loser; } } while(0)
-#define SEC_CHECK2(CALL, ERROR, ARG) do { rv = CALL; if (rv) \
- { sec_error(ERROR ": %s", ARG, sec_errstr(rv)); goto loser; } } while(0)
-
-// @@@ Remove this
-#if 1
-
-static CSSM_KEYUSE CERT_KeyUsageForCertUsage(SECCertUsage certUsage)
-{
- switch (certUsage)
- {
- case certUsageSSLClient: return CSSM_KEYUSE_SIGN;
- case certUsageSSLServer: return CSSM_KEYUSE_SIGN;
- case certUsageSSLServerWithStepUp: return CSSM_KEYUSE_SIGN;
- case certUsageSSLCA: return CSSM_KEYUSE_SIGN;
- case certUsageEmailSigner: return CSSM_KEYUSE_SIGN;
- case certUsageEmailRecipient: return CSSM_KEYUSE_UNWRAP;
- case certUsageObjectSigner: return CSSM_KEYUSE_SIGN;
- case certUsageUserCertImport: return CSSM_KEYUSE_SIGN;
- case certUsageVerifyCA: return CSSM_KEYUSE_SIGN;
- case certUsageProtectedObjectSigner: return CSSM_KEYUSE_SIGN;
- case certUsageStatusResponder: return CSSM_KEYUSE_SIGN;
- case certUsageAnyCA: return CSSM_KEYUSE_SIGN;
- default:
- sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage);
- return CSSM_KEYUSE_SIGN;
- }
-}
-
-static SecPolicyRef CERT_PolicyForCertUsage(SECCertUsage certUsage, const char *emailAddress)
-{
- SecPolicyRef policy = NULL;
- const CSSM_OID *policyOID;
- OSStatus rv;
-
- switch (certUsage)
- {
- case certUsageSSLClient: policyOID = &CSSMOID_APPLE_TP_SSL; break;
- case certUsageSSLServer: policyOID = &CSSMOID_APPLE_TP_SSL; break;
- case certUsageSSLServerWithStepUp: policyOID = &CSSMOID_APPLE_TP_SSL; break;
- case certUsageSSLCA: policyOID = &CSSMOID_APPLE_TP_SSL; break;
- case certUsageEmailSigner: policyOID = &CSSMOID_APPLE_TP_SMIME; break;
- case certUsageEmailRecipient: policyOID = &CSSMOID_APPLE_TP_SMIME; break;
- case certUsageObjectSigner: policyOID = &CSSMOID_APPLE_TP_CODE_SIGN; break;
- case certUsageUserCertImport: policyOID = &CSSMOID_APPLE_X509_BASIC; break;
- case certUsageVerifyCA: policyOID = &CSSMOID_APPLE_X509_BASIC; break;
- case certUsageProtectedObjectSigner: policyOID = &CSSMOID_APPLE_ISIGN; break;
- case certUsageStatusResponder: policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP; break;
- case certUsageAnyCA: policyOID = &CSSMOID_APPLE_X509_BASIC; break;
- default:
- sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage);
- goto loser;
- }
-
- SEC_CHECK(SecPolicyCopy(CSSM_CERT_X_509v3, policyOID, &policy), "SecPolicyCopy");
- if (certUsage == certUsageEmailSigner || certUsage == certUsageEmailRecipient)
- {
- CSSM_APPLE_TP_SMIME_OPTIONS options =
- {
- CSSM_APPLE_TP_SMIME_OPTS_VERSION,
- certUsage == certUsageEmailSigner
- ? CE_KU_DigitalSignature | CE_KU_NonRepudiation
- : CE_KU_KeyEncipherment,
- emailAddress ? sizeof(emailAddress) : 0,
- emailAddress
- };
- CSSM_DATA value = { sizeof(options), (uint8 *)&options };
- if (SecPolicySetValue(policy, &value)) {
- goto loser;
- }
- }
-
- // @@@ Need to set values for SSL and other policies.
- return policy;
-
-loser:
- if (policy) CFRelease(policy);
- return NULL;
-}
-
-static SecCertificateRef CERT_FindUserCertByUsage(CFTypeRef keychainOrArray, const char *emailAddress,
- SECCertUsage certUsage, Boolean validOnly)
-{
- SecKeychainSearchRef search = NULL;
- SecCertificateRef cert = NULL;
- SecPolicyRef policy;
- OSStatus rv;
-
- policy = CERT_PolicyForCertUsage(certUsage, emailAddress);
- if (!policy)
- goto loser;
-
- SEC_CHECK2(SecKeychainSearchCreateForCertificateByEmail(keychainOrArray, emailAddress, &search),
- "create search for certificate with email: \"%s\"", emailAddress);
- for (;;)
- {
- SecKeychainItemRef item;
- rv = SecKeychainSearchCopyNext(search, &item);
- if (rv)
- {
- if (rv == errSecItemNotFound)
- break;
-
- sec_perror("error finding next matching certificate", rv);
- goto loser;
- }
-
- cert = (SecCertificateRef)item;
- // @@@ Check cert against policy.
- }
-
-loser:
- if (policy) CFRelease(policy);
- if (search) CFRelease(search);
-
- return cert;
-}
-
-static SecIdentityRef CERT_FindIdentityByUsage(CFTypeRef keychainOrArray,
- const char *emailAddress,
- SECCertUsage certUsage,
- Boolean validOnly)
-{
- SecIdentitySearchRef search = NULL;
- SecIdentityRef identity = NULL;
- CFStringRef idString = CFStringCreateWithCString(NULL, emailAddress, kCFStringEncodingUTF8);
- SecPolicyRef policy;
- OSStatus rv;
-
- policy = CERT_PolicyForCertUsage(certUsage, emailAddress);
- if (!policy)
- goto loser;
-
-
- SEC_CHECK2(SecIdentitySearchCreateWithPolicy(policy, idString,
- CERT_KeyUsageForCertUsage(certUsage), keychainOrArray, validOnly, &search),
- "create search for identity with email: \"%s\"", emailAddress);
- for (;;)
- {
- rv = SecIdentitySearchCopyNext(search, &identity);
- if (rv)
- {
- if (rv == errSecItemNotFound)
- break;
-
- sec_perror("error finding next matching identity", rv);
- goto loser;
- }
- }
-
-loser:
- if (policy) CFRelease(policy);
- if (search) CFRelease(search);
- if (idString) CFRelease(idString);
-
- return identity;
-
-
-#if 0
- SecIdentityRef identity = NULL;
- SecCertificateRef cert;
- OSStatus rv;
-
- cert = CERT_FindUserCertByUsage(keychainOrArray, emailAddress, certUsage, validOnly);
- if (!cert)
- goto loser;
-
- SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray, cert, &identity),
- "failed to find private key for certificate with email: \"%s\"", emailAddress);
-loser:
- if (cert) CFRelease(cert);
-
- return identity;
-#endif
-}
-
-static SecCertificateRef CERT_FindCertByNicknameOrEmailAddr(CFTypeRef keychainOrArray, const char *emailAddress)
-{
- SecCertificateRef certificate = NULL;
- OSStatus rv;
-
- SEC_CHECK2(SecCertificateFindByEmail(keychainOrArray, emailAddress, &certificate),
- "failed to find certificate with email: \"%s\"", emailAddress);
-
-loser:
- return certificate;
-}
-
-static SecIdentityRef CERT_FindIdentityBySubjectKeyID(CFTypeRef keychainOrArray,
- const char *subjectKeyIDString)
-{
- // ss will be something like "B2ACD31AC8D0DA62E7679432ADDD3398EF66948B"
-
- SecCertificateRef certificate = NULL;
- SecIdentityRef identityRef = NULL;
- OSStatus rv;
-
- CSSM_SIZE len = strlen(subjectKeyIDString)/2;
- CSSM_DATA subjectKeyID = {0,};
- subjectKeyID.Length = len;
- subjectKeyID.Data = (uint8 *)malloc(subjectKeyID.Length);
- fromHex(subjectKeyIDString, &subjectKeyID);
-
- SEC_CHECK2(SecCertificateFindBySubjectKeyID(keychainOrArray, &subjectKeyID, &certificate),
- "failed to find identity with subject key ID: \"%s\"", subjectKeyIDString);
-
- SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identityRef),
- "failed to find certificate with subject key ID: \"%s\"", subjectKeyIDString);
-loser:
- return identityRef;
-}
-
-
-static OSStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage)
-{
- return 0;
-}
-
-#endif
-
-// @@@ Eleminate usage of this header.
-//#include "cert.h"
-//#include <security_asn1/secerr.h>
-//#include "plgetopt.h"
-//#include "secitem.h"
-
-#ifdef HAVE_DODUMPSTATES
-extern int doDumpStates;
-#endif /* HAVE_DODUMPSTATES */
-
-OSStatus SECU_FileToItem(CSSM_DATA *dst, FILE *src);
-
-
-extern void SEC_Init(void); /* XXX */
-static int cms_verbose = 0;
-static int cms_update_single_byte = 0;
-
-/* XXX stolen from cmsarray.c
- * nss_CMSArray_Count - count number of elements in array
- */
-static int nss_CMSArray_Count(void **array)
-{
- int n = 0;
- if (array == NULL)
- return 0;
- while (*array++ != NULL)
- n++;
- return n;
-}
-
-typedef OSStatus(update_func)(void *cx, const char *data, size_t len);
-
-static OSStatus do_update(update_func *update,
- void *cx, const unsigned char *data, size_t len)
-{
- OSStatus rv = noErr;
- if (cms_update_single_byte)
- {
- for (;len; --len, ++data)
- {
- rv = update(cx, (const char *)data, 1);
- if (rv)
- break;
- }
- }
- else
- rv = update(cx, (const char *)data, len);
-
- return rv;
-}
-
-
-static OSStatus DigestFile(SecArenaPoolRef poolp, CSSM_DATA ***digests, CSSM_DATA *input, SECAlgorithmID **algids)
-{
- SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(algids);
- if (digcx == NULL)
- return paramErr;
-
- do_update((update_func *)SecCmsDigestContextUpdate, digcx, input->Data, input->Length);
-
- return SecCmsDigestContextFinishMultiple(digcx, poolp, digests);
-}
-
-static char *
-ownpw(void *info, Boolean retry, void *arg)
-{
- char * passwd = NULL;
-
- if ( (!retry) && arg ) {
- passwd = strdup((char *)arg);
- }
-
- return passwd;
-}
-
-struct optionsStr {
- PK11PasswordFunc password;
- SECCertUsage certUsage;
- SecKeychainRef certDBHandle;
-};
-
-struct decodeOptionsStr {
- struct optionsStr *options;
- FILE *contentFile;
- int headerLevel;
- Boolean suppressContent;
- SecCmsGetDecryptKeyCallback dkcb;
- SecSymmetricKeyRef bulkkey;
-};
-
-struct signOptionsStr {
- struct optionsStr *options;
- char *nickname;
- char *encryptionKeyPreferenceNick;
- char *subjectKeyID;
- Boolean signingTime;
- Boolean smimeProfile;
- Boolean detached;
- SECOidTag hashAlgTag;
- Boolean wantTimestamping;
- char *timestampingURL;
-};
-
-struct envelopeOptionsStr {
- struct optionsStr *options;
- char **recipients;
-};
-
-struct certsonlyOptionsStr {
- struct optionsStr *options;
- char **recipients;
-};
-
-struct encryptOptionsStr {
- struct optionsStr *options;
- char **recipients;
- SecCmsMessageRef envmsg;
- CSSM_DATA *input;
- FILE *outfile;
- FILE *envFile;
- SecSymmetricKeyRef bulkkey;
- SECOidTag bulkalgtag;
- int keysize;
-};
-
-static SecCmsMessageRef decode(FILE *out, CSSM_DATA *output, CSSM_DATA *input,
- const struct decodeOptionsStr *decodeOptions)
-{
- SecCmsDecoderRef dcx;
- SecCmsMessageRef cmsg=NULL;
- SecCmsContentInfoRef cinfo;
- SecCmsSignedDataRef sigd = NULL;
- SecCmsEnvelopedDataRef envd;
- SecCmsEncryptedDataRef encd;
- SECAlgorithmID **digestalgs;
- int nlevels, i, nsigners, j;
- CFStringRef signercn;
- SecCmsSignerInfoRef si;
- SECOidTag typetag;
- CSSM_DATA **digests;
- SecArenaPoolRef poolp = NULL;
- PK11PasswordFunc pwcb;
- void *pwcb_arg;
- CSSM_DATA *item, sitem = { 0, };
- CFTypeRef policy = NULL;
- OSStatus rv;
-
- pwcb = (PK11PasswordFunc)((decodeOptions->options->password != NULL) ? ownpw : NULL);
- pwcb_arg = (decodeOptions->options->password != NULL) ?
- (void *)decodeOptions->options->password : NULL;
-
- if (decodeOptions->contentFile) // detached content: grab content file
- SECU_FileToItem(&sitem, decodeOptions->contentFile);
-
- SEC_CHECK(SecCmsDecoderCreate(NULL,
- NULL, NULL, /* content callback */
- pwcb, pwcb_arg, /* password callback */
- decodeOptions->dkcb, /* decrypt key callback */
- decodeOptions->bulkkey,
- &dcx),
- "failed to create to decoder");
- SEC_CHECK(do_update((update_func *)SecCmsDecoderUpdate, dcx, input->Data, input->Length),
- "failed to add data to decoder");
- SEC_CHECK(SecCmsDecoderFinish(dcx, &cmsg),
- "failed to decode message");
-
- if (decodeOptions->headerLevel >= 0)
- {
- /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
- fprintf(out, "SMIME: ");
- }
-
- nlevels = SecCmsMessageContentLevelCount(cmsg);
- for (i = 0; i < nlevels; i++)
- {
- cinfo = SecCmsMessageContentLevel(cmsg, i);
- typetag = SecCmsContentInfoGetContentTypeTag(cinfo);
-
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "\tlevel=%d.%d; ", decodeOptions->headerLevel, nlevels - i);
-
- switch (typetag)
- {
- case SEC_OID_PKCS7_SIGNED_DATA:
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "type=signedData; ");
-
- SEC_CHECK0(sigd = (SecCmsSignedDataRef )SecCmsContentInfoGetContent(cinfo),
- "problem finding signedData component");
- /* if we have a content file, but no digests for this signedData */
- if (decodeOptions->contentFile != NULL && !SecCmsSignedDataHasDigests(sigd))
- {
- SEC_CHECK(SecArenaPoolCreate(1024, &poolp), "failed to create arenapool");
- digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
- SEC_CHECK(DigestFile(poolp, &digests, &sitem, digestalgs),
- "problem computing message digest");
- SEC_CHECK(SecCmsSignedDataSetDigests(sigd, digestalgs, digests),
- "problem setting message digests");
- SecArenaPoolFree(poolp, false);
- }
-
- policy = CERT_PolicyForCertUsage(decodeOptions->options->certUsage, NULL);
- // import the certificates
- SEC_CHECK(SecCmsSignedDataImportCerts(sigd,decodeOptions->options->certDBHandle,
- decodeOptions->options->certUsage, true /* false */),
- "cert import failed");
-
- /* find out about signers */
- nsigners = SecCmsSignedDataSignerInfoCount(sigd);
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "nsigners=%d; ", nsigners);
- if (nsigners == 0)
- {
- /* must be a cert transport message */
- OSStatus rv;
- /* XXX workaround for bug #54014 */
- SecCmsSignedDataImportCerts(sigd,decodeOptions->options->certDBHandle,
- decodeOptions->options->certUsage,true);
- SEC_CHECK(SecCmsSignedDataVerifyCertsOnly(sigd,decodeOptions->options->certDBHandle, policy),
- "verify certs-only failed");
- return cmsg;
- }
-
- SEC_CHECK0(SecCmsSignedDataHasDigests(sigd), "message has no digests");
- for (j = 0; j < nsigners; j++)
- {
- si = SecCmsSignedDataGetSignerInfo(sigd, j);
- signercn = SecCmsSignerInfoGetSignerCommonName(si);
- if (decodeOptions->headerLevel >= 0)
- {
- const char *px = signercn ? CFStringGetCStringPtr(signercn,kCFStringEncodingMacRoman) : "<NULL>";
- fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, px);
- }
- SecCmsSignedDataVerifySignerInfo(sigd, j, decodeOptions->options->certDBHandle,
- policy, NULL);
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "signer%d.status=%s; ", j,
- SecCmsUtilVerificationStatusToString(SecCmsSignerInfoGetVerificationStatus(si)));
- /* XXX what do we do if we don't print headers? */
- }
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "type=envelopedData; ");
- envd = (SecCmsEnvelopedDataRef )SecCmsContentInfoGetContent(cinfo);
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "type=encryptedData; ");
- encd = (SecCmsEncryptedDataRef )SecCmsContentInfoGetContent(cinfo);
- break;
- case SEC_OID_PKCS7_DATA:
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "type=data; ");
- break;
- default:
- break;
- }
- if (decodeOptions->headerLevel >= 0)
- fprintf(out, "\n");
- }
-
- if (!decodeOptions->suppressContent)
- {
- item = decodeOptions->contentFile ? &sitem :
- SecCmsMessageGetContent(cmsg);
- /* Copy the data. */
- output->Length = item->Length;
- output->Data = malloc(output->Length);
- memcpy(output->Data, item->Data, output->Length);
- }
-
- if (policy) CFRelease(policy);
-
- return cmsg;
-loser:
- if (policy) CFRelease(policy);
- if (cmsg) SecCmsMessageDestroy(cmsg);
- return NULL;
-}
-
-/* example of a callback function to use with encoder */
-/*
-static void
-writeout(void *arg, const char *buf, unsigned long len)
-{
- FILE *f = (FILE *)arg;
-
- if (f != NULL && buf != NULL)
- (void)fwrite(buf, len, 1, f);
-}
-*/
-
-static SecCmsMessageRef signed_data(struct signOptionsStr *signOptions)
-{
- SecCmsMessageRef cmsg = NULL;
- SecCmsContentInfoRef cinfo;
- SecCmsSignedDataRef sigd;
- SecCmsSignerInfoRef signerinfo;
- SecIdentityRef identity = NULL;
- SecCertificateRef cert = NULL, ekpcert = NULL;
- OSStatus rv;
-
- if (cms_verbose)
- {
- fprintf(stderr, "Input to signed_data:\n");
- if (signOptions->options->password)
- fprintf(stderr, "password [%s]\n", "***" /*signOptions->options->password*/);
- else
- fprintf(stderr, "password [NULL]\n");
- fprintf(stderr, "certUsage [%d]\n", signOptions->options->certUsage);
- if (signOptions->options->certDBHandle)
- fprintf(stderr, "certdb [%p]\n", signOptions->options->certDBHandle);
- else
- fprintf(stderr, "certdb [NULL]\n");
- if (signOptions->nickname)
- fprintf(stderr, "nickname [%s]\n", signOptions->nickname);
- else
- fprintf(stderr, "nickname [NULL]\n");
- if (signOptions->subjectKeyID)
- fprintf(stderr, "subject Key ID [%s]\n", signOptions->subjectKeyID);
- }
-
- if (signOptions->subjectKeyID)
- {
- if ((identity = CERT_FindIdentityBySubjectKeyID(signOptions->options->certDBHandle,
- signOptions->subjectKeyID)) == NULL)
- {
- sec_error("could not find signing identity for subject key ID: \"%s\"", signOptions->subjectKeyID);
- return NULL;
- }
-
- if (cms_verbose)
- fprintf(stderr, "Found identity for subject key ID %s\n", signOptions->subjectKeyID);
- }
- else if (signOptions->nickname)
- {
- if ((identity = CERT_FindIdentityByUsage(signOptions->options->certDBHandle,
- signOptions->nickname,
- signOptions->options->certUsage,
- false)) == NULL)
- {
- // look for identity by common name rather than email address
- if ((identity = CopyMatchingIdentity(signOptions->options->certDBHandle,
- signOptions->nickname,
- NULL,
- signOptions->options->certUsage)) == NULL)
- {
- sec_error("could not find signing identity for name: \"%s\"", signOptions->nickname);
- return NULL;
- }
- }
-
- if (cms_verbose)
- fprintf(stderr, "Found identity for %s\n", signOptions->nickname);
- }
- else
- {
- // no identity was specified
- sec_error("no signing identity was specified");
- return NULL;
- }
-
- // Get the cert from the identity
- SEC_CHECK(SecIdentityCopyCertificate(identity, &cert),
- "SecIdentityCopyCertificate");
- // create the message object on its own pool
- SEC_CHECK0(cmsg = SecCmsMessageCreate(NULL), "cannot create CMS message");
- // build chain of objects: message->signedData->data
- SEC_CHECK0(sigd = SecCmsSignedDataCreate(cmsg),
- "cannot create CMS signedData object");
- SEC_CHECK0(cinfo = SecCmsMessageGetContentInfo(cmsg),
- "message has no content info");
- SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd),
- "cannot attach CMS signedData object");
- SEC_CHECK0(cinfo = SecCmsSignedDataGetContentInfo(sigd),
- "signed data has no content info");
- /* we're always passing data in and detaching optionally */
- SEC_CHECK(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, signOptions->detached),
- "cannot attach CMS data object");
- // create & attach signer information
- SEC_CHECK0(signerinfo = SecCmsSignerInfoCreate(cmsg, identity, signOptions->hashAlgTag),
- "cannot create CMS signerInfo object");
- if (cms_verbose)
- fprintf(stderr,"Created CMS message, added signed data w/ signerinfo\n");
-
- // we want the cert chain included for this one
- SEC_CHECK(SecCmsSignerInfoIncludeCerts(signerinfo, SecCmsCMCertChain, signOptions->options->certUsage),
- "cannot add cert chain");
-
- if (cms_verbose)
- fprintf(stderr, "imported certificate\n");
-
- if (signOptions->signingTime)
- SEC_CHECK(SecCmsSignerInfoAddSigningTime(signerinfo, CFAbsoluteTimeGetCurrent()),
- "cannot add signingTime attribute");
-
- if (signOptions->smimeProfile)
- SEC_CHECK(SecCmsSignerInfoAddSMIMECaps(signerinfo),
- "cannot add SMIMECaps attribute");
-
- if (signOptions->wantTimestamping)
- {
- CFErrorRef error = NULL;
- SecCmsMessageSetTSAContext(cmsg, SecCmsTSAGetDefaultContext(&error));
- }
-
- if (!signOptions->encryptionKeyPreferenceNick)
- {
- /* check signing cert for fitness as encryption cert */
- OSStatus FitForEncrypt = CERT_CheckCertUsage(cert, certUsageEmailRecipient);
-
- if (noErr == FitForEncrypt)
- {
- /* if yes, add signing cert as EncryptionKeyPreference */
- SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo, cert, signOptions->options->certDBHandle),
- "cannot add default SMIMEEncKeyPrefs attribute");
- SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo, cert, signOptions->options->certDBHandle),
- "cannot add default MS SMIMEEncKeyPrefs attribute");
- }
- else
- {
- /* this is a dual-key cert case, we need to look for the encryption
- certificate under the same nickname as the signing cert */
- /* get the cert, add it to the message */
- if ((ekpcert = CERT_FindUserCertByUsage(
- signOptions->options->certDBHandle,
- signOptions->nickname,
- certUsageEmailRecipient,
- false)) == NULL)
- {
- sec_error("can find encryption cert for \"%s\"", signOptions->nickname);
- goto loser;
- }
-
- SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo, ekpcert,signOptions->options->certDBHandle),
- "cannot add SMIMEEncKeyPrefs attribute");
- SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo, ekpcert,signOptions->options->certDBHandle),
- "cannot add MS SMIMEEncKeyPrefs attribute");
- SEC_CHECK(SecCmsSignedDataAddCertificate(sigd, ekpcert),
- "cannot add encryption certificate");
- }
- }
- else if (strcmp(signOptions->encryptionKeyPreferenceNick, "NONE") == 0)
- {
- /* No action */
- }
- else
- {
- /* specific email address for encryption preferred encryption cert specified.
- get the cert, add it to the message */
- if ((ekpcert = CERT_FindUserCertByUsage(
- signOptions->options->certDBHandle,
- signOptions->encryptionKeyPreferenceNick,
- certUsageEmailRecipient, false)) == NULL)
- {
- sec_error("can find encryption cert for \"%s\"", signOptions->encryptionKeyPreferenceNick);
- goto loser;
- }
-
- SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo, ekpcert,signOptions->options->certDBHandle),
- "cannot add SMIMEEncKeyPrefs attribute");
- SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo, ekpcert,signOptions->options->certDBHandle),
- "cannot add MS SMIMEEncKeyPrefs attribute");
- SEC_CHECK(SecCmsSignedDataAddCertificate(sigd, ekpcert),
- "cannot add encryption certificate");
- }
-
- SEC_CHECK(SecCmsSignedDataAddSignerInfo(sigd, signerinfo),
- "cannot add CMS signerInfo object");
-
- if (cms_verbose)
- fprintf(stderr, "created signed-data message\n");
-
- if (ekpcert) CFRelease(ekpcert);
- if (cert) CFRelease(cert);
- if (identity) CFRelease(identity);
- return cmsg;
-
-loser:
- if (ekpcert) CFRelease(ekpcert);
- if (cert) CFRelease(cert);
- if (identity) CFRelease(identity);
- SecCmsMessageDestroy(cmsg);
- return NULL;
-}
-
-static SecCmsMessageRef enveloped_data(struct envelopeOptionsStr *envelopeOptions)
-{
- SecCmsMessageRef cmsg = NULL;
- SecCmsContentInfoRef cinfo;
- SecCmsEnvelopedDataRef envd;
- SecCmsRecipientInfoRef recipientinfo;
- SecCertificateRef *recipientcerts = NULL;
- SecKeychainRef dbhandle;
- SECOidTag bulkalgtag;
- OSStatus rv;
- int keysize, i = 0;
- int cnt;
-
- dbhandle = envelopeOptions->options->certDBHandle;
- /* count the recipients */
- SEC_CHECK0(cnt = nss_CMSArray_Count((void **)envelopeOptions->recipients),
- "please name at least one recipient");
-
- // @@@ find the recipient's certs by email address or nickname
- if ((recipientcerts = (SecCertificateRef *)calloc((cnt+1), sizeof(SecCertificateRef))) == NULL)
- {
- sec_error("failed to alloc certs array: %s", strerror(errno));
- goto loser;
- }
-
- for (i = 0; envelopeOptions->recipients[i] != NULL; ++i)
- {
- if ((recipientcerts[i] =
- CERT_FindCertByNicknameOrEmailAddr(dbhandle, envelopeOptions->recipients[i])) == NULL)
- {
- i = 0;
- goto loser;
- }
- }
-
- recipientcerts[i] = NULL;
- i = 0;
-
- // find a nice bulk algorithm
- SEC_CHECK(SecSMIMEFindBulkAlgForRecipients(recipientcerts, &bulkalgtag, &keysize),
- "cannot find common bulk algorithm");
- // create the message object on its own pool
- SEC_CHECK0(cmsg = SecCmsMessageCreate(NULL), "cannot create CMS message");
- // build chain of objects: message->envelopedData->data
- SEC_CHECK0(envd = SecCmsEnvelopedDataCreate(cmsg, bulkalgtag, keysize),
- "cannot create CMS envelopedData object");
- SEC_CHECK0(cinfo = SecCmsMessageGetContentInfo(cmsg),
- "message has no content info");
- SEC_CHECK(SecCmsContentInfoSetContentEnvelopedData(cmsg, cinfo, envd),
- "cannot attach CMS envelopedData object");
- SEC_CHECK0(cinfo = SecCmsEnvelopedDataGetContentInfo(envd),
- "enveloped data has no content info");
- // We're always passing data in, so the content is NULL
- SEC_CHECK(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false),
- "cannot attach CMS data object");
-
- // create & attach recipient information
- for (i = 0; recipientcerts[i] != NULL; i++)
- {
- SEC_CHECK0(recipientinfo = SecCmsRecipientInfoCreate(cmsg, recipientcerts[i]),
- "cannot create CMS recipientInfo object");
- SEC_CHECK(SecCmsEnvelopedDataAddRecipient(envd, recipientinfo),
- "cannot add CMS recipientInfo object");
- CFRelease(recipientcerts[i]);
- }
-
- if (recipientcerts)
- free(recipientcerts);
-
- return cmsg;
-loser:
- if (recipientcerts)
- {
- for (; recipientcerts[i] != NULL; i++)
- CFRelease(recipientcerts[i]);
- }
-
- if (cmsg)
- SecCmsMessageDestroy(cmsg);
-
- if (recipientcerts)
- free(recipientcerts);
-
- return NULL;
-}
-
-static SecSymmetricKeyRef dkcb(void *arg, SECAlgorithmID *algid)
-{
- return (SecSymmetricKeyRef)arg;
-}
-
-static OSStatus get_enc_params(struct encryptOptionsStr *encryptOptions)
-{
- struct envelopeOptionsStr envelopeOptions;
- OSStatus rv = paramErr;
- SecCmsMessageRef env_cmsg = NULL;
- SecCmsContentInfoRef cinfo;
- int i, nlevels;
-
- // construct an enveloped data message to obtain bulk keys
- if (encryptOptions->envmsg)
- env_cmsg = encryptOptions->envmsg; // get it from an old message
- else
- {
- CSSM_DATA dummyOut = { 0, };
- CSSM_DATA dummyIn = { 0, };
- char str[] = "Hello!";
- SecArenaPoolRef tmparena = NULL;
-
- SEC_CHECK(SecArenaPoolCreate(1024, &tmparena), "failed to create arenapool");
-
- dummyIn.Data = (unsigned char *)str;
- dummyIn.Length = strlen(str);
- envelopeOptions.options = encryptOptions->options;
- envelopeOptions.recipients = encryptOptions->recipients;
- env_cmsg = enveloped_data(&envelopeOptions);
- rv = SecCmsMessageEncode(env_cmsg, &dummyIn, tmparena, &dummyOut);
- if (rv) {
- goto loser;
- }
- fwrite(dummyOut.Data, 1, dummyOut.Length,encryptOptions->envFile);
-
- SecArenaPoolFree(tmparena, false);
- }
-
- // get the content info for the enveloped data
- nlevels = SecCmsMessageContentLevelCount(env_cmsg);
- for (i = 0; i < nlevels; i++)
- {
- SECOidTag typetag;
- cinfo = SecCmsMessageContentLevel(env_cmsg, i);
- typetag = SecCmsContentInfoGetContentTypeTag(cinfo);
- if (typetag == SEC_OID_PKCS7_DATA)
- {
- // get the symmetric key
- encryptOptions->bulkalgtag = SecCmsContentInfoGetContentEncAlgTag(cinfo);
- encryptOptions->keysize = SecCmsContentInfoGetBulkKeySize(cinfo);
- encryptOptions->bulkkey = SecCmsContentInfoGetBulkKey(cinfo);
- rv = noErr;
- break;
- }
- }
- if (i == nlevels)
- sec_error("could not retrieve enveloped data: messsage has: %ld levels", nlevels);
-
-loser:
- if (env_cmsg)
- SecCmsMessageDestroy(env_cmsg);
-
- return rv;
-}
-
-static SecCmsMessageRef encrypted_data(struct encryptOptionsStr *encryptOptions)
-{
- OSStatus rv = paramErr;
- SecCmsMessageRef cmsg = NULL;
- SecCmsContentInfoRef cinfo;
- SecCmsEncryptedDataRef encd;
- SecCmsEncoderRef ecx = NULL;
- SecArenaPoolRef tmppoolp = NULL;
- CSSM_DATA derOut = { 0, };
-
- /* arena for output */
- SEC_CHECK(SecArenaPoolCreate(1024, &tmppoolp), "failed to create arenapool");
- // create the message object on its own pool
- SEC_CHECK0(cmsg = SecCmsMessageCreate(NULL), "cannot create CMS message");
- // build chain of objects: message->encryptedData->data
- SEC_CHECK0(encd = SecCmsEncryptedDataCreate(cmsg, encryptOptions->bulkalgtag,
- encryptOptions->keysize),
- "cannot create CMS encryptedData object");
- SEC_CHECK0(cinfo = SecCmsMessageGetContentInfo(cmsg),
- "message has no content info");
- SEC_CHECK(SecCmsContentInfoSetContentEncryptedData(cmsg, cinfo, encd),
- "cannot attach CMS encryptedData object");
- SEC_CHECK0(cinfo = SecCmsEncryptedDataGetContentInfo(encd),
- "encrypted data has no content info");
- /* we're always passing data in, so the content is NULL */
- SEC_CHECK(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false),
- "cannot attach CMS data object");
- SEC_CHECK(SecCmsEncoderCreate(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
- dkcb, encryptOptions->bulkkey, NULL, NULL, &ecx),
- "cannot create encoder context");
- SEC_CHECK(do_update((update_func *)SecCmsEncoderUpdate, ecx, encryptOptions->input->Data,
- encryptOptions->input->Length),
- "failed to add data to encoder");
- SEC_CHECK(SecCmsEncoderFinish(ecx), "failed to encrypt data");
- fwrite(derOut.Data, derOut.Length, 1, encryptOptions->outfile);
- /* @@@ Check and report write errors. */
- /*
- if (bulkkey)
- CFRelease(bulkkey);
- */
-
- if (tmppoolp)
- SecArenaPoolFree(tmppoolp, false);
- return cmsg;
-loser:
- /*
- if (bulkkey)
- CFRelease(bulkkey);
- */
- if (tmppoolp)
- SecArenaPoolFree(tmppoolp, false);
- if (cmsg)
- SecCmsMessageDestroy(cmsg);
-
- return NULL;
-}
-
-static SecCmsMessageRef signed_data_certsonly(struct certsonlyOptionsStr *certsonlyOptions)
-{
- SecCmsMessageRef cmsg = NULL;
- SecCmsContentInfoRef cinfo;
- SecCmsSignedDataRef sigd;
- SecCertificateRef *certs = NULL;
- SecKeychainRef dbhandle;
- OSStatus rv;
-
- int i = 0, cnt;
- dbhandle = certsonlyOptions->options->certDBHandle;
- SEC_CHECK0(cnt = nss_CMSArray_Count((void**)certsonlyOptions->recipients),
- "please indicate the nickname of a certificate to sign with");
- if ((certs = (SecCertificateRef *)calloc((cnt+1), sizeof(SecCertificateRef))) == NULL)
- {
- sec_error("failed to alloc certs array: %s", strerror(errno));
- goto loser;
- }
- for (i=0; certsonlyOptions->recipients && certsonlyOptions->recipients[i] != NULL; i++)
- {
- if ((certs[i] = CERT_FindCertByNicknameOrEmailAddr(dbhandle,certsonlyOptions->recipients[i])) == NULL)
- {
- i=0;
- goto loser;
- }
- }
- certs[i] = NULL;
- i = 0;
- // create the message object on its own pool
- SEC_CHECK0(cmsg = SecCmsMessageCreate(NULL), "cannot create CMS message");
- // build chain of objects: message->signedData->data
- SEC_CHECK0(sigd = SecCmsSignedDataCreateCertsOnly(cmsg, certs[0], true),
- "cannot create certs only CMS signedData object");
- CFReleaseNull(certs[0]);
- for (i = 1; i < cnt; ++i)
- {
- SEC_CHECK2(SecCmsSignedDataAddCertChain(sigd, certs[i]),
- "cannot add cert chain for \"%s\"", certsonlyOptions->recipients[i]);
- CFReleaseNull(certs[i]);
- }
-
- SEC_CHECK0(cinfo = SecCmsMessageGetContentInfo(cmsg),
- "message has no content info");
- SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd),
- "cannot attach CMS signedData object");
- SEC_CHECK0(cinfo = SecCmsSignedDataGetContentInfo(sigd),
- "signed data has no content info");
- SEC_CHECK(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false),
- "cannot attach CMS data object");
-
- if (certs)
- free(certs);
-
- return cmsg;
-loser:
- if (certs)
- {
- for (; i < cnt; ++i)
- CFReleaseNull(certs[i]);
-
- free(certs);
- }
- if (cmsg) SecCmsMessageDestroy(cmsg);
-
- return NULL;
-}
-
-typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
-
-int cms_util(int argc, char * const *argv)
-{
- FILE *outFile;
- SecCmsMessageRef cmsg = NULL;
- FILE *inFile;
- int ch;
- Mode mode = UNKNOWN;
- PK11PasswordFunc pwcb;
- void *pwcb_arg;
- struct decodeOptionsStr decodeOptions = { 0 };
- struct signOptionsStr signOptions = { 0 };
- struct envelopeOptionsStr envelopeOptions = { 0 };
- struct certsonlyOptionsStr certsonlyOptions = { 0 };
- struct encryptOptionsStr encryptOptions = { 0 };
- struct optionsStr options = { 0 };
- int result = 1;
- static char *ptrarray[128] = { 0 };
- int nrecipients = 0;
- char *str, *tok;
- char *envFileName;
- const char *keychainName = NULL;
- CSSM_DATA input = { 0,};
- CSSM_DATA output = { 0,};
- CSSM_DATA dummy = { 0, };
- CSSM_DATA envmsg = { 0, };
- OSStatus rv;
-
- inFile = stdin;
- outFile = stdout;
- envFileName = NULL;
- mode = UNKNOWN;
- decodeOptions.contentFile = NULL;
- decodeOptions.suppressContent = false;
- decodeOptions.headerLevel = -1;
- options.certUsage = certUsageEmailSigner;
- options.password = NULL;
- signOptions.nickname = NULL;
- signOptions.subjectKeyID = NULL;
- signOptions.detached = false;
- signOptions.signingTime = false;
- signOptions.smimeProfile = false;
- signOptions.encryptionKeyPreferenceNick = NULL;
- signOptions.hashAlgTag = SEC_OID_SHA1;
- envelopeOptions.recipients = NULL;
- encryptOptions.recipients = NULL;
- encryptOptions.envmsg = NULL;
- encryptOptions.envFile = NULL;
- encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
- encryptOptions.bulkkey = NULL;
- encryptOptions.keysize = -1;
-
- // Parse command line arguments
- while ((ch = getopt(argc, argv, "CDEGH:N:OPSTY:Z:c:de:h:i:k:no:p:r:su:vt:")) != -1)
- {
- switch (ch)
- {
- case 'C':
- mode = ENCRYPT;
- break;
- case 'D':
- mode = DECODE;
- break;
- case 'E':
- mode = ENVELOPE;
- break;
- case 'G':
- if (mode != SIGN) {
- sec_error("option -G only supported with option -S");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.signingTime = true;
- break;
- case 'H':
- if (mode != SIGN) {
- sec_error("option -n only supported with option -D");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- if(!optarg) {
- result = 2;
- goto loser;
- }
- decodeOptions.suppressContent = true;
- if (!strcmp(optarg, "MD2"))
- signOptions.hashAlgTag = SEC_OID_MD2;
- else if (!strcmp(optarg, "MD4"))
- signOptions.hashAlgTag = SEC_OID_MD4;
- else if (!strcmp(optarg, "MD5"))
- signOptions.hashAlgTag = SEC_OID_MD5;
- else if (!strcmp(optarg, "SHA1"))
- signOptions.hashAlgTag = SEC_OID_SHA1;
- else if (!strcmp(optarg, "SHA256"))
- signOptions.hashAlgTag = SEC_OID_SHA256;
- else if (!strcmp(optarg, "SHA384"))
- signOptions.hashAlgTag = SEC_OID_SHA384;
- else if (!strcmp(optarg, "SHA512"))
- signOptions.hashAlgTag = SEC_OID_SHA512;
- else {
- sec_error("option -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512");
- goto loser;
- }
- break;
- case 'N':
- if (mode != SIGN) {
- sec_error("option -N only supported with option -S");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.nickname = strdup(optarg);
- break;
- case 'O':
- mode = CERTSONLY;
- break;
- case 'P':
- if (mode != SIGN) {
- sec_error("option -P only supported with option -S");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.smimeProfile = true;
- break;
- case 'S':
- mode = SIGN;
- break;
- case 'T':
- if (mode != SIGN) {
- sec_error("option -T only supported with option -S");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.detached = true;
- break;
- case 'Y':
- if (mode != SIGN) {
- sec_error("option -Y only supported with option -S");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.encryptionKeyPreferenceNick = strdup(optarg);
- break;
-
- case 'c':
- if (mode != DECODE)
- {
- sec_error("option -c only supported with option -D");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- if ((decodeOptions.contentFile = fopen(optarg, "rb")) == NULL)
- {
- sec_error("unable to open \"%s\" for reading: %s", optarg, strerror(errno));
- result = 1;
- goto loser;
- }
- break;
-
-#ifdef HAVE_DODUMPSTATES
- case 'd':
- doDumpStates++;
- break;
-#endif /* HAVE_DODUMPSTATES */
-
- case 'e':
- envFileName = strdup(optarg);
- encryptOptions.envFile = fopen(envFileName, "rb"); // PR_RDONLY, 00660);
- break;
-
- case 'h':
- if (mode != DECODE) {
- sec_error("option -h only supported with option -D");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- decodeOptions.headerLevel = atoi(optarg);
- if (decodeOptions.headerLevel < 0) {
- sec_error("option -h cannot have a negative value");
- goto loser;
- }
- break;
- case 'i':
- inFile = fopen(optarg,"rb"); // PR_RDONLY, 00660);
- if (inFile == NULL)
- {
- sec_error("unable to open \"%s\" for reading: %s", optarg, strerror(errno));
- goto loser;
- }
- break;
-
- case 'k':
- keychainName = optarg;
- break;
-
- case 'n':
- if (mode != DECODE)
- {
- sec_error("option -n only supported with option -D");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- decodeOptions.suppressContent = true;
- break;
- case 'o':
- outFile = fopen(optarg, "wb");
- if (outFile == NULL)
- {
- sec_error("unable to open \"%s\" for writing: %s", optarg, strerror(errno));
- goto loser;
- }
- break;
- case 'p':
- if (!optarg)
- {
- sec_error("option -p must have a value");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
-
- options.password = (PK11PasswordFunc)ownpw;//strdup(optarg);
- break;
-
- case 'r':
- if (!optarg)
- {
- sec_error("option -r must have a value");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
-
- envelopeOptions.recipients = ptrarray;
- str = (char *)optarg;
- do {
- tok = strchr(str, ',');
- if (tok) *tok = '\0';
- envelopeOptions.recipients[nrecipients++] = strdup(str);
- if (tok) str = tok + 1;
- } while (tok);
- envelopeOptions.recipients[nrecipients] = NULL;
- encryptOptions.recipients = envelopeOptions.recipients;
- certsonlyOptions.recipients = envelopeOptions.recipients;
- break;
-
- case 's':
- cms_update_single_byte = 1;
- break;
-
- case 'Z':
- if (!optarg)
- {
- sec_error("option -Z must have a value");
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- signOptions.subjectKeyID = strdup(optarg);
-
- break;
-
- case 'u':
- {
- int usageType = atoi (optarg);
- if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
- {
- result = 1;
- goto loser;
- }
- options.certUsage = (SECCertUsage)usageType;
- break;
- }
- case 'v':
- cms_verbose = 1;
- break;
- case 't':
- if (optarg)
- signOptions.timestampingURL = strdup(optarg);
- signOptions.wantTimestamping = true;
- break;
- default:
- result = 2; /* Trigger usage message. */
- goto loser;
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc != 0 || mode == UNKNOWN)
- {
- result = 2; /* Trigger usage message. */
- goto loser;
- }
-
- result = 0;
-
- if (mode != CERTSONLY)
- SECU_FileToItem(&input, inFile);
- if (inFile != stdin)
- fclose(inFile);
- if (cms_verbose)
- fprintf(stderr, "received commands\n");
-
- /* Call the libsec initialization routines */
- if (keychainName)
- {
- check_obsolete_keychain(keychainName);
- options.certDBHandle = keychain_open(keychainName);
- if (!options.certDBHandle)
- {
- sec_perror("SecKeychainOpen", errSecInvalidKeychain);
- result = 1;
- goto loser;
- }
- }
-
- if (cms_verbose)
- fprintf(stderr, "Got default certdb\n");
-
- switch (mode)
- {
- case DECODE:
- decodeOptions.options = &options;
- if (encryptOptions.envFile)
- {
- /* Decoding encrypted-data, so get the bulkkey from an
- * enveloped-data message.
- */
- SECU_FileToItem(&envmsg, encryptOptions.envFile);
- decodeOptions.options = &options;
- encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, &decodeOptions);
- if (!encryptOptions.envmsg)
- {
- sec_error("problem decoding env msg");
- result = 1;
- break;
- }
- rv = get_enc_params(&encryptOptions);
- decodeOptions.dkcb = dkcb;
- decodeOptions.bulkkey = encryptOptions.bulkkey;
- }
- cmsg = decode(outFile, &output, &input, &decodeOptions);
- if (!cmsg)
- {
- sec_error("problem decoding");
- result = 1;
- }
- fwrite(output.Data, output.Length, 1, outFile);
- break;
- case SIGN:
- signOptions.options = &options;
- cmsg = signed_data(&signOptions);
- if (!cmsg)
- {
- sec_error("problem signing");
- result = 1;
- }
- break;
- case ENCRYPT:
- if (!envFileName)
- {
- sec_error("you must specify an envelope file with -e");
- result = 1;
- goto loser;
- }
- encryptOptions.options = &options;
- encryptOptions.input = &input;
- encryptOptions.outfile = outFile;
- if (!encryptOptions.envFile) {
- encryptOptions.envFile = fopen(envFileName,"wb"); //PR_WRONLY|PR_CREATE_FILE, 00660);
- if (!encryptOptions.envFile)
- {
- sec_error("failed to create file %s: %s", envFileName, strerror(errno));
- result = 1;
- goto loser;
- }
- }
- else
- {
- SECU_FileToItem(&envmsg, encryptOptions.envFile);
- decodeOptions.options = &options;
- encryptOptions.envmsg = decode(NULL, &dummy, &envmsg,
- &decodeOptions);
- if (encryptOptions.envmsg == NULL)
- {
- sec_error("problem decrypting env msg");
- result = 1;
- break;
- }
- }
-
- /* decode an enveloped-data message to get the bulkkey (create
- * a new one if neccessary)
- */
- rv = get_enc_params(&encryptOptions);
- /* create the encrypted-data message */
- cmsg = encrypted_data(&encryptOptions);
- if (!cmsg)
- {
- sec_error("problem encrypting");
- result = 1;
- }
-
- if (encryptOptions.bulkkey)
- {
- CFRelease(encryptOptions.bulkkey);
- encryptOptions.bulkkey = NULL;
- }
- break;
- case ENVELOPE:
- envelopeOptions.options = &options;
- cmsg = enveloped_data(&envelopeOptions);
- if (!cmsg)
- {
- sec_error("problem enveloping");
- result = 1;
- }
- break;
- case CERTSONLY:
- certsonlyOptions.options = &options;
- cmsg = signed_data_certsonly(&certsonlyOptions);
- if (!cmsg)
- {
- sec_error("problem with certs-only");
- result = 1;
- }
- break;
- case UNKNOWN:
- /* Already handled above. */
- break;
- }
-
- if ( (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY)
- && (!result) )
- {
- SecArenaPoolRef arena = NULL;
- SecCmsEncoderRef ecx;
- CSSM_DATA output = {};
-
- SEC_CHECK(SecArenaPoolCreate(1024, &arena), "failed to create arenapool");
- pwcb = (PK11PasswordFunc)((options.password != NULL) ? ownpw : NULL);
- pwcb_arg = (options.password != NULL) ? (void *)options.password : NULL;
- if (cms_verbose) {
- fprintf(stderr, "cmsg [%p]\n", cmsg);
- fprintf(stderr, "arena [%p]\n", arena);
- if (pwcb_arg)
- fprintf(stderr, "password [%s]\n", (char *)pwcb_arg);
- else
- fprintf(stderr, "password [NULL]\n");
- }
-
- SEC_CHECK(SecCmsEncoderCreate(cmsg,
- NULL, NULL, /* DER output callback */
- &output, arena, /* destination storage */
- pwcb, pwcb_arg, /* password callback */
- NULL, NULL, /* decrypt key callback */
- NULL, NULL, /* detached digests */
- &ecx),
- "cannot create encoder context");
- if (cms_verbose)
- {
- fprintf(stderr, "input len [%ld]\n", input.Length);
- {
- unsigned int j;
- for (j = 0; j < input.Length; ++j)
- fprintf(stderr, "%2x%c", input.Data[j], (j>0&&j%35==0)?'\n':' ');
- }
- }
-
- if (input.Length > 0) { /* skip if certs-only (or other zero content) */
- SEC_CHECK(SecCmsEncoderUpdate(ecx, (char *)input.Data, input.Length),
- "failed to add data to encoder");
- }
-
- SEC_CHECK(SecCmsEncoderFinish(ecx), "failed to encode data");
-
- if (cms_verbose) {
- fprintf(stderr, "encoding passed\n");
- }
-
- /*PR_Write(output.data, output.len);*/
- fwrite(output.Data, output.Length, 1, outFile);
- if (cms_verbose) {
- fprintf(stderr, "wrote to file\n");
- }
- SecArenaPoolFree(arena, false);
- }
-
-loser:
- if(signOptions.encryptionKeyPreferenceNick) {
- free(signOptions.encryptionKeyPreferenceNick);
- }
- if(signOptions.nickname) {
- free(signOptions.nickname);
- }
- if(signOptions.subjectKeyID) {
- free(signOptions.subjectKeyID);
- }
- if(signOptions.timestampingURL) {
- free(signOptions.timestampingURL);
- }
- if(envFileName) {
- free(envFileName);
- }
- if (cmsg)
- SecCmsMessageDestroy(cmsg);
- if (outFile != stdout)
- fclose(outFile);
-
- if (decodeOptions.contentFile)
- fclose(decodeOptions.contentFile);
-
- return result;
-}
-
-
-#pragma mark ================ Misc from NSS ===================
-// from /security/nss/cmd/lib/secutil.c
-
-OSStatus
-SECU_FileToItem(CSSM_DATA *dst, FILE *src)
-{
- const int kReadSize = 4096;
- size_t bytesRead, totalRead = 0;
-
- do
- {
- /* Make room in dst for the new data. */
- dst->Length += kReadSize;
- dst->Data = realloc(dst->Data, dst->Length);
- if (!dst->Data)
- return 1 /* @@@ memFullErr */;
-
- bytesRead = fread (&dst->Data[totalRead], 1, kReadSize, src);
- totalRead += bytesRead;
- } while (bytesRead == kReadSize);
-
- if (!feof (src))
- {
- /* We are here, but there's no EOF. This is bad */
- if (dst->Data) {
- free(dst->Data);
- dst->Data = NULL;
- dst->Length = 0;
- }
- return 1 /* @@@ ioErr */;
- }
-
- /* Trim down the buffer. */
- dst->Length = totalRead;
- dst->Data = realloc(dst->Data, totalRead);
- if (!dst->Data)
- return 1 /* @@@ memFullErr */;
-
- return noErr;
-}