2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Netscape security libraries.
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
35 * Modifications Copyright (c) 2003-2009,2012,2014 Apple Inc. All Rights Reserved.
37 * cmsutil -- A command to work with CMS data
40 #include "security_tool.h"
41 #include "keychain_utilities.h"
42 #include "identity_find.h"
44 #include <Security/SecCmsBase.h>
45 #include <Security/SecCmsContentInfo.h>
46 #include <Security/SecCmsDecoder.h>
47 #include <Security/SecCmsDigestContext.h>
48 #include <Security/SecCmsDigestedData.h>
49 #include <Security/SecCmsEncoder.h>
50 #include <Security/SecCmsEncryptedData.h>
51 #include <Security/SecCmsEnvelopedData.h>
52 #include <Security/SecCmsMessage.h>
53 #include <Security/SecCmsRecipientInfo.h>
54 #include <Security/SecCmsSignedData.h>
55 #include <Security/SecCmsSignerInfo.h>
56 #include <Security/SecSMIME.h>
57 #include <Security/tsaSupport.h>
59 #include <Security/oidsalg.h>
60 #include <Security/SecPolicy.h>
61 #include <Security/SecKeychain.h>
62 #include <Security/SecKeychainSearch.h>
63 #include <Security/SecIdentity.h>
64 #include <Security/SecIdentitySearch.h>
65 #include <CoreFoundation/CFString.h>
66 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
67 #include <utilities/SecCFRelease.h>
78 #include <Security/SecPolicyPriv.h>
79 // SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindBySubjectKeyID, SecCertificateFindByEmail
80 #include <Security/SecCertificatePriv.h>
81 // SecIdentitySearchCreateWithPolicy
82 #include <Security/SecIdentitySearchPriv.h>
84 #define SEC_CHECK0(CALL, ERROR) do { if (!(CALL)) { sec_error(ERROR); goto loser; } } while(0)
85 #define SEC_CHECK(CALL, ERROR) do { rv = (CALL); if (rv) { sec_perror(ERROR, rv); goto loser; } } while(0)
86 #define SEC_CHECK2(CALL, ERROR, ARG) do { rv = CALL; if (rv) \
87 { sec_error(ERROR ": %s", ARG, sec_errstr(rv)); goto loser; } } while(0)
92 static CSSM_KEYUSE
CERT_KeyUsageForCertUsage(SECCertUsage certUsage
)
96 case certUsageSSLClient
: return CSSM_KEYUSE_SIGN
;
97 case certUsageSSLServer
: return CSSM_KEYUSE_SIGN
;
98 case certUsageSSLServerWithStepUp
: return CSSM_KEYUSE_SIGN
;
99 case certUsageSSLCA
: return CSSM_KEYUSE_SIGN
;
100 case certUsageEmailSigner
: return CSSM_KEYUSE_SIGN
;
101 case certUsageEmailRecipient
: return CSSM_KEYUSE_UNWRAP
;
102 case certUsageObjectSigner
: return CSSM_KEYUSE_SIGN
;
103 case certUsageUserCertImport
: return CSSM_KEYUSE_SIGN
;
104 case certUsageVerifyCA
: return CSSM_KEYUSE_SIGN
;
105 case certUsageProtectedObjectSigner
: return CSSM_KEYUSE_SIGN
;
106 case certUsageStatusResponder
: return CSSM_KEYUSE_SIGN
;
107 case certUsageAnyCA
: return CSSM_KEYUSE_SIGN
;
109 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
110 return CSSM_KEYUSE_SIGN
;
114 static SecPolicyRef
CERT_PolicyForCertUsage(SECCertUsage certUsage
, const char *emailAddress
)
116 SecPolicyRef policy
= NULL
;
117 const CSSM_OID
*policyOID
;
122 case certUsageSSLClient
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
123 case certUsageSSLServer
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
124 case certUsageSSLServerWithStepUp
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
125 case certUsageSSLCA
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
126 case certUsageEmailSigner
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
127 case certUsageEmailRecipient
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
128 case certUsageObjectSigner
: policyOID
= &CSSMOID_APPLE_TP_CODE_SIGN
; break;
129 case certUsageUserCertImport
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
130 case certUsageVerifyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
131 case certUsageProtectedObjectSigner
: policyOID
= &CSSMOID_APPLE_ISIGN
; break;
132 case certUsageStatusResponder
: policyOID
= &CSSMOID_APPLE_TP_REVOCATION_OCSP
; break;
133 case certUsageAnyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
135 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
139 SEC_CHECK(SecPolicyCopy(CSSM_CERT_X_509v3
, policyOID
, &policy
), "SecPolicyCopy");
140 if (certUsage
== certUsageEmailSigner
|| certUsage
== certUsageEmailRecipient
)
142 CSSM_APPLE_TP_SMIME_OPTIONS options
=
144 CSSM_APPLE_TP_SMIME_OPTS_VERSION
,
145 certUsage
== certUsageEmailSigner
146 ? CE_KU_DigitalSignature
| CE_KU_NonRepudiation
147 : CE_KU_KeyEncipherment
,
148 emailAddress
? sizeof(emailAddress
) : 0,
151 CSSM_DATA value
= { sizeof(options
), (uint8
*)&options
};
152 if (SecPolicySetValue(policy
, &value
)) {
157 // @@@ Need to set values for SSL and other policies.
161 if (policy
) CFRelease(policy
);
165 static SecCertificateRef
CERT_FindUserCertByUsage(CFTypeRef keychainOrArray
, const char *emailAddress
,
166 SECCertUsage certUsage
, Boolean validOnly
)
168 SecKeychainSearchRef search
= NULL
;
169 SecCertificateRef cert
= NULL
;
173 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
177 SEC_CHECK2(SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &search
),
178 "create search for certificate with email: \"%s\"", emailAddress
);
181 SecKeychainItemRef item
;
182 rv
= SecKeychainSearchCopyNext(search
, &item
);
185 if (rv
== errSecItemNotFound
)
188 sec_perror("error finding next matching certificate", rv
);
192 cert
= (SecCertificateRef
)item
;
193 // @@@ Check cert against policy.
197 if (policy
) CFRelease(policy
);
198 if (search
) CFRelease(search
);
203 static SecIdentityRef
CERT_FindIdentityByUsage(CFTypeRef keychainOrArray
,
204 const char *emailAddress
,
205 SECCertUsage certUsage
,
208 SecIdentitySearchRef search
= NULL
;
209 SecIdentityRef identity
= NULL
;
210 CFStringRef idString
= CFStringCreateWithCString(NULL
, emailAddress
, kCFStringEncodingUTF8
);
214 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
219 SEC_CHECK2(SecIdentitySearchCreateWithPolicy(policy
, idString
,
220 CERT_KeyUsageForCertUsage(certUsage
), keychainOrArray
, validOnly
, &search
),
221 "create search for identity with email: \"%s\"", emailAddress
);
224 rv
= SecIdentitySearchCopyNext(search
, &identity
);
227 if (rv
== errSecItemNotFound
)
230 sec_perror("error finding next matching identity", rv
);
236 if (policy
) CFRelease(policy
);
237 if (search
) CFRelease(search
);
238 if (idString
) CFRelease(idString
);
244 SecIdentityRef identity
= NULL
;
245 SecCertificateRef cert
;
248 cert
= CERT_FindUserCertByUsage(keychainOrArray
, emailAddress
, certUsage
, validOnly
);
252 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, cert
, &identity
),
253 "failed to find private key for certificate with email: \"%s\"", emailAddress
);
255 if (cert
) CFRelease(cert
);
261 static SecCertificateRef
CERT_FindCertByNicknameOrEmailAddr(CFTypeRef keychainOrArray
, const char *emailAddress
)
263 SecCertificateRef certificate
= NULL
;
266 SEC_CHECK2(SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificate
),
267 "failed to find certificate with email: \"%s\"", emailAddress
);
273 static SecIdentityRef
CERT_FindIdentityBySubjectKeyID(CFTypeRef keychainOrArray
,
274 const char *subjectKeyIDString
)
276 // ss will be something like "B2ACD31AC8D0DA62E7679432ADDD3398EF66948B"
278 SecCertificateRef certificate
= NULL
;
279 SecIdentityRef identityRef
= NULL
;
282 CSSM_SIZE len
= strlen(subjectKeyIDString
)/2;
283 CSSM_DATA subjectKeyID
= {0,};
284 subjectKeyID
.Length
= len
;
285 subjectKeyID
.Data
= (uint8
*)malloc(subjectKeyID
.Length
);
286 fromHex(subjectKeyIDString
, &subjectKeyID
);
288 SEC_CHECK2(SecCertificateFindBySubjectKeyID(keychainOrArray
, &subjectKeyID
, &certificate
),
289 "failed to find identity with subject key ID: \"%s\"", subjectKeyIDString
);
291 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, certificate
, &identityRef
),
292 "failed to find certificate with subject key ID: \"%s\"", subjectKeyIDString
);
298 static OSStatus
CERT_CheckCertUsage (SecCertificateRef cert
,unsigned char usage
)
305 // @@@ Eleminate usage of this header.
307 //#include <security_asn1/secerr.h>
308 //#include "plgetopt.h"
309 //#include "secitem.h"
311 #ifdef HAVE_DODUMPSTATES
312 extern int doDumpStates
;
313 #endif /* HAVE_DODUMPSTATES */
315 OSStatus
SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
);
318 extern void SEC_Init(void); /* XXX */
319 static int cms_verbose
= 0;
320 static int cms_update_single_byte
= 0;
322 /* XXX stolen from cmsarray.c
323 * nss_CMSArray_Count - count number of elements in array
325 static int nss_CMSArray_Count(void **array
)
330 while (*array
++ != NULL
)
335 typedef OSStatus(update_func
)(void *cx
, const char *data
, size_t len
);
337 static OSStatus
do_update(update_func
*update
,
338 void *cx
, const unsigned char *data
, size_t len
)
341 if (cms_update_single_byte
)
343 for (;len
; --len
, ++data
)
345 rv
= update(cx
, (const char *)data
, 1);
351 rv
= update(cx
, (const char *)data
, len
);
357 static OSStatus
DigestFile(SecArenaPoolRef poolp
, CSSM_DATA
***digests
, CSSM_DATA
*input
, SECAlgorithmID
**algids
)
359 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(algids
);
363 do_update((update_func
*)SecCmsDigestContextUpdate
, digcx
, input
->Data
, input
->Length
);
365 return SecCmsDigestContextFinishMultiple(digcx
, poolp
, digests
);
369 ownpw(void *info
, Boolean retry
, void *arg
)
371 char * passwd
= NULL
;
373 if ( (!retry
) && arg
) {
374 passwd
= strdup((char *)arg
);
381 PK11PasswordFunc password
;
382 SECCertUsage certUsage
;
383 SecKeychainRef certDBHandle
;
386 struct decodeOptionsStr
{
387 struct optionsStr
*options
;
390 Boolean suppressContent
;
391 SecCmsGetDecryptKeyCallback dkcb
;
392 SecSymmetricKeyRef bulkkey
;
395 struct signOptionsStr
{
396 struct optionsStr
*options
;
398 char *encryptionKeyPreferenceNick
;
401 Boolean smimeProfile
;
403 SECOidTag hashAlgTag
;
404 Boolean wantTimestamping
;
405 char *timestampingURL
;
408 struct envelopeOptionsStr
{
409 struct optionsStr
*options
;
413 struct certsonlyOptionsStr
{
414 struct optionsStr
*options
;
418 struct encryptOptionsStr
{
419 struct optionsStr
*options
;
421 SecCmsMessageRef envmsg
;
425 SecSymmetricKeyRef bulkkey
;
426 SECOidTag bulkalgtag
;
430 static SecCmsMessageRef
decode(FILE *out
, CSSM_DATA
*output
, CSSM_DATA
*input
,
431 const struct decodeOptionsStr
*decodeOptions
)
433 SecCmsDecoderRef dcx
;
434 SecCmsMessageRef cmsg
=NULL
;
435 SecCmsContentInfoRef cinfo
;
436 SecCmsSignedDataRef sigd
= NULL
;
437 SecCmsEnvelopedDataRef envd
;
438 SecCmsEncryptedDataRef encd
;
439 SECAlgorithmID
**digestalgs
;
440 int nlevels
, i
, nsigners
, j
;
441 CFStringRef signercn
;
442 SecCmsSignerInfoRef si
;
445 SecArenaPoolRef poolp
= NULL
;
446 PK11PasswordFunc pwcb
;
448 CSSM_DATA
*item
, sitem
= { 0, };
449 CFTypeRef policy
= NULL
;
452 pwcb
= (PK11PasswordFunc
)((decodeOptions
->options
->password
!= NULL
) ? ownpw
: NULL
);
453 pwcb_arg
= (decodeOptions
->options
->password
!= NULL
) ?
454 (void *)decodeOptions
->options
->password
: NULL
;
456 if (decodeOptions
->contentFile
) // detached content: grab content file
457 SECU_FileToItem(&sitem
, decodeOptions
->contentFile
);
459 SEC_CHECK(SecCmsDecoderCreate(NULL
,
460 NULL
, NULL
, /* content callback */
461 pwcb
, pwcb_arg
, /* password callback */
462 decodeOptions
->dkcb
, /* decrypt key callback */
463 decodeOptions
->bulkkey
,
465 "failed to create to decoder");
466 SEC_CHECK(do_update((update_func
*)SecCmsDecoderUpdate
, dcx
, input
->Data
, input
->Length
),
467 "failed to add data to decoder");
468 SEC_CHECK(SecCmsDecoderFinish(dcx
, &cmsg
),
469 "failed to decode message");
471 if (decodeOptions
->headerLevel
>= 0)
473 /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
474 fprintf(out
, "SMIME: ");
477 nlevels
= SecCmsMessageContentLevelCount(cmsg
);
478 for (i
= 0; i
< nlevels
; i
++)
480 cinfo
= SecCmsMessageContentLevel(cmsg
, i
);
481 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
483 if (decodeOptions
->headerLevel
>= 0)
484 fprintf(out
, "\tlevel=%d.%d; ", decodeOptions
->headerLevel
, nlevels
- i
);
488 case SEC_OID_PKCS7_SIGNED_DATA
:
489 if (decodeOptions
->headerLevel
>= 0)
490 fprintf(out
, "type=signedData; ");
492 SEC_CHECK0(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
),
493 "problem finding signedData component");
494 /* if we have a content file, but no digests for this signedData */
495 if (decodeOptions
->contentFile
!= NULL
&& !SecCmsSignedDataHasDigests(sigd
))
497 SEC_CHECK(SecArenaPoolCreate(1024, &poolp
), "failed to create arenapool");
498 digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
499 SEC_CHECK(DigestFile(poolp
, &digests
, &sitem
, digestalgs
),
500 "problem computing message digest");
501 SEC_CHECK(SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
),
502 "problem setting message digests");
503 SecArenaPoolFree(poolp
, false);
506 policy
= CERT_PolicyForCertUsage(decodeOptions
->options
->certUsage
, NULL
);
507 // import the certificates
508 SEC_CHECK(SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
509 decodeOptions
->options
->certUsage
, true /* false */),
510 "cert import failed");
512 /* find out about signers */
513 nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
514 if (decodeOptions
->headerLevel
>= 0)
515 fprintf(out
, "nsigners=%d; ", nsigners
);
518 /* must be a cert transport message */
520 /* XXX workaround for bug #54014 */
521 SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
522 decodeOptions
->options
->certUsage
,true);
523 SEC_CHECK(SecCmsSignedDataVerifyCertsOnly(sigd
,decodeOptions
->options
->certDBHandle
, policy
),
524 "verify certs-only failed");
528 SEC_CHECK0(SecCmsSignedDataHasDigests(sigd
), "message has no digests");
529 for (j
= 0; j
< nsigners
; j
++)
531 si
= SecCmsSignedDataGetSignerInfo(sigd
, j
);
532 signercn
= SecCmsSignerInfoGetSignerCommonName(si
);
533 if (decodeOptions
->headerLevel
>= 0)
535 const char *px
= signercn
? CFStringGetCStringPtr(signercn
,kCFStringEncodingMacRoman
) : "<NULL>";
536 fprintf(out
, "\n\t\tsigner%d.id=\"%s\"; ", j
, px
);
538 SecCmsSignedDataVerifySignerInfo(sigd
, j
, decodeOptions
->options
->certDBHandle
,
540 if (decodeOptions
->headerLevel
>= 0)
541 fprintf(out
, "signer%d.status=%s; ", j
,
542 SecCmsUtilVerificationStatusToString(SecCmsSignerInfoGetVerificationStatus(si
)));
543 /* XXX what do we do if we don't print headers? */
546 case SEC_OID_PKCS7_ENVELOPED_DATA
:
547 if (decodeOptions
->headerLevel
>= 0)
548 fprintf(out
, "type=envelopedData; ");
549 envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
);
551 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
552 if (decodeOptions
->headerLevel
>= 0)
553 fprintf(out
, "type=encryptedData; ");
554 encd
= (SecCmsEncryptedDataRef
)SecCmsContentInfoGetContent(cinfo
);
556 case SEC_OID_PKCS7_DATA
:
557 if (decodeOptions
->headerLevel
>= 0)
558 fprintf(out
, "type=data; ");
563 if (decodeOptions
->headerLevel
>= 0)
567 if (!decodeOptions
->suppressContent
)
569 item
= decodeOptions
->contentFile
? &sitem
:
570 SecCmsMessageGetContent(cmsg
);
572 output
->Length
= item
->Length
;
573 output
->Data
= malloc(output
->Length
);
574 memcpy(output
->Data
, item
->Data
, output
->Length
);
577 if (policy
) CFRelease(policy
);
581 if (policy
) CFRelease(policy
);
582 if (cmsg
) SecCmsMessageDestroy(cmsg
);
586 /* example of a callback function to use with encoder */
589 writeout(void *arg, const char *buf, unsigned long len)
591 FILE *f = (FILE *)arg;
593 if (f != NULL && buf != NULL)
594 (void)fwrite(buf, len, 1, f);
598 static SecCmsMessageRef
signed_data(struct signOptionsStr
*signOptions
)
600 SecCmsMessageRef cmsg
= NULL
;
601 SecCmsContentInfoRef cinfo
;
602 SecCmsSignedDataRef sigd
;
603 SecCmsSignerInfoRef signerinfo
;
604 SecIdentityRef identity
= NULL
;
605 SecCertificateRef cert
= NULL
, ekpcert
= NULL
;
610 fprintf(stderr
, "Input to signed_data:\n");
611 if (signOptions
->options
->password
)
612 fprintf(stderr
, "password [%s]\n", "***" /*signOptions->options->password*/);
614 fprintf(stderr
, "password [NULL]\n");
615 fprintf(stderr
, "certUsage [%d]\n", signOptions
->options
->certUsage
);
616 if (signOptions
->options
->certDBHandle
)
617 fprintf(stderr
, "certdb [%p]\n", signOptions
->options
->certDBHandle
);
619 fprintf(stderr
, "certdb [NULL]\n");
620 if (signOptions
->nickname
)
621 fprintf(stderr
, "nickname [%s]\n", signOptions
->nickname
);
623 fprintf(stderr
, "nickname [NULL]\n");
624 if (signOptions
->subjectKeyID
)
625 fprintf(stderr
, "subject Key ID [%s]\n", signOptions
->subjectKeyID
);
628 if (signOptions
->subjectKeyID
)
630 if ((identity
= CERT_FindIdentityBySubjectKeyID(signOptions
->options
->certDBHandle
,
631 signOptions
->subjectKeyID
)) == NULL
)
633 sec_error("could not find signing identity for subject key ID: \"%s\"", signOptions
->subjectKeyID
);
638 fprintf(stderr
, "Found identity for subject key ID %s\n", signOptions
->subjectKeyID
);
640 else if (signOptions
->nickname
)
642 if ((identity
= CERT_FindIdentityByUsage(signOptions
->options
->certDBHandle
,
643 signOptions
->nickname
,
644 signOptions
->options
->certUsage
,
647 // look for identity by common name rather than email address
648 if ((identity
= CopyMatchingIdentity(signOptions
->options
->certDBHandle
,
649 signOptions
->nickname
,
651 signOptions
->options
->certUsage
)) == NULL
)
653 sec_error("could not find signing identity for name: \"%s\"", signOptions
->nickname
);
659 fprintf(stderr
, "Found identity for %s\n", signOptions
->nickname
);
663 // no identity was specified
664 sec_error("no signing identity was specified");
668 // Get the cert from the identity
669 SEC_CHECK(SecIdentityCopyCertificate(identity
, &cert
),
670 "SecIdentityCopyCertificate");
671 // create the message object on its own pool
672 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
673 // build chain of objects: message->signedData->data
674 SEC_CHECK0(sigd
= SecCmsSignedDataCreate(cmsg
),
675 "cannot create CMS signedData object");
676 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
677 "message has no content info");
678 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
679 "cannot attach CMS signedData object");
680 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
681 "signed data has no content info");
682 /* we're always passing data in and detaching optionally */
683 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, signOptions
->detached
),
684 "cannot attach CMS data object");
685 // create & attach signer information
686 SEC_CHECK0(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, signOptions
->hashAlgTag
),
687 "cannot create CMS signerInfo object");
689 fprintf(stderr
,"Created CMS message, added signed data w/ signerinfo\n");
691 // we want the cert chain included for this one
692 SEC_CHECK(SecCmsSignerInfoIncludeCerts(signerinfo
, SecCmsCMCertChain
, signOptions
->options
->certUsage
),
693 "cannot add cert chain");
696 fprintf(stderr
, "imported certificate\n");
698 if (signOptions
->signingTime
)
699 SEC_CHECK(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()),
700 "cannot add signingTime attribute");
702 if (signOptions
->smimeProfile
)
703 SEC_CHECK(SecCmsSignerInfoAddSMIMECaps(signerinfo
),
704 "cannot add SMIMECaps attribute");
706 if (signOptions
->wantTimestamping
)
708 CFErrorRef error
= NULL
;
709 SecCmsMessageSetTSAContext(cmsg
, SecCmsTSAGetDefaultContext(&error
));
712 if (!signOptions
->encryptionKeyPreferenceNick
)
714 /* check signing cert for fitness as encryption cert */
715 OSStatus FitForEncrypt
= CERT_CheckCertUsage(cert
, certUsageEmailRecipient
);
717 if (noErr
== FitForEncrypt
)
719 /* if yes, add signing cert as EncryptionKeyPreference */
720 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
721 "cannot add default SMIMEEncKeyPrefs attribute");
722 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
723 "cannot add default MS SMIMEEncKeyPrefs attribute");
727 /* this is a dual-key cert case, we need to look for the encryption
728 certificate under the same nickname as the signing cert */
729 /* get the cert, add it to the message */
730 if ((ekpcert
= CERT_FindUserCertByUsage(
731 signOptions
->options
->certDBHandle
,
732 signOptions
->nickname
,
733 certUsageEmailRecipient
,
736 sec_error("can find encryption cert for \"%s\"", signOptions
->nickname
);
740 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
741 "cannot add SMIMEEncKeyPrefs attribute");
742 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
743 "cannot add MS SMIMEEncKeyPrefs attribute");
744 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
745 "cannot add encryption certificate");
748 else if (strcmp(signOptions
->encryptionKeyPreferenceNick
, "NONE") == 0)
754 /* specific email address for encryption preferred encryption cert specified.
755 get the cert, add it to the message */
756 if ((ekpcert
= CERT_FindUserCertByUsage(
757 signOptions
->options
->certDBHandle
,
758 signOptions
->encryptionKeyPreferenceNick
,
759 certUsageEmailRecipient
, false)) == NULL
)
761 sec_error("can find encryption cert for \"%s\"", signOptions
->encryptionKeyPreferenceNick
);
765 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
766 "cannot add SMIMEEncKeyPrefs attribute");
767 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
768 "cannot add MS SMIMEEncKeyPrefs attribute");
769 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
770 "cannot add encryption certificate");
773 SEC_CHECK(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
),
774 "cannot add CMS signerInfo object");
777 fprintf(stderr
, "created signed-data message\n");
779 if (ekpcert
) CFRelease(ekpcert
);
780 if (cert
) CFRelease(cert
);
781 if (identity
) CFRelease(identity
);
785 if (ekpcert
) CFRelease(ekpcert
);
786 if (cert
) CFRelease(cert
);
787 if (identity
) CFRelease(identity
);
788 SecCmsMessageDestroy(cmsg
);
792 static SecCmsMessageRef
enveloped_data(struct envelopeOptionsStr
*envelopeOptions
)
794 SecCmsMessageRef cmsg
= NULL
;
795 SecCmsContentInfoRef cinfo
;
796 SecCmsEnvelopedDataRef envd
;
797 SecCmsRecipientInfoRef recipientinfo
;
798 SecCertificateRef
*recipientcerts
= NULL
;
799 SecKeychainRef dbhandle
;
800 SECOidTag bulkalgtag
;
805 dbhandle
= envelopeOptions
->options
->certDBHandle
;
806 /* count the recipients */
807 SEC_CHECK0(cnt
= nss_CMSArray_Count((void **)envelopeOptions
->recipients
),
808 "please name at least one recipient");
810 // @@@ find the recipient's certs by email address or nickname
811 if ((recipientcerts
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
813 sec_error("failed to alloc certs array: %s", strerror(errno
));
817 for (i
= 0; envelopeOptions
->recipients
[i
] != NULL
; ++i
)
819 if ((recipientcerts
[i
] =
820 CERT_FindCertByNicknameOrEmailAddr(dbhandle
, envelopeOptions
->recipients
[i
])) == NULL
)
827 recipientcerts
[i
] = NULL
;
830 // find a nice bulk algorithm
831 SEC_CHECK(SecSMIMEFindBulkAlgForRecipients(recipientcerts
, &bulkalgtag
, &keysize
),
832 "cannot find common bulk algorithm");
833 // create the message object on its own pool
834 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
835 // build chain of objects: message->envelopedData->data
836 SEC_CHECK0(envd
= SecCmsEnvelopedDataCreate(cmsg
, bulkalgtag
, keysize
),
837 "cannot create CMS envelopedData object");
838 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
839 "message has no content info");
840 SEC_CHECK(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
),
841 "cannot attach CMS envelopedData object");
842 SEC_CHECK0(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
),
843 "enveloped data has no content info");
844 // We're always passing data in, so the content is NULL
845 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
846 "cannot attach CMS data object");
848 // create & attach recipient information
849 for (i
= 0; recipientcerts
[i
] != NULL
; i
++)
851 SEC_CHECK0(recipientinfo
= SecCmsRecipientInfoCreate(cmsg
, recipientcerts
[i
]),
852 "cannot create CMS recipientInfo object");
853 SEC_CHECK(SecCmsEnvelopedDataAddRecipient(envd
, recipientinfo
),
854 "cannot add CMS recipientInfo object");
855 CFRelease(recipientcerts
[i
]);
859 free(recipientcerts
);
865 for (; recipientcerts
[i
] != NULL
; i
++)
866 CFRelease(recipientcerts
[i
]);
870 SecCmsMessageDestroy(cmsg
);
873 free(recipientcerts
);
878 static SecSymmetricKeyRef
dkcb(void *arg
, SECAlgorithmID
*algid
)
880 return (SecSymmetricKeyRef
)arg
;
883 static OSStatus
get_enc_params(struct encryptOptionsStr
*encryptOptions
)
885 struct envelopeOptionsStr envelopeOptions
;
886 OSStatus rv
= paramErr
;
887 SecCmsMessageRef env_cmsg
= NULL
;
888 SecCmsContentInfoRef cinfo
;
891 // construct an enveloped data message to obtain bulk keys
892 if (encryptOptions
->envmsg
)
893 env_cmsg
= encryptOptions
->envmsg
; // get it from an old message
896 CSSM_DATA dummyOut
= { 0, };
897 CSSM_DATA dummyIn
= { 0, };
898 char str
[] = "Hello!";
899 SecArenaPoolRef tmparena
= NULL
;
901 SEC_CHECK(SecArenaPoolCreate(1024, &tmparena
), "failed to create arenapool");
903 dummyIn
.Data
= (unsigned char *)str
;
904 dummyIn
.Length
= strlen(str
);
905 envelopeOptions
.options
= encryptOptions
->options
;
906 envelopeOptions
.recipients
= encryptOptions
->recipients
;
907 env_cmsg
= enveloped_data(&envelopeOptions
);
908 rv
= SecCmsMessageEncode(env_cmsg
, &dummyIn
, tmparena
, &dummyOut
);
912 fwrite(dummyOut
.Data
, 1, dummyOut
.Length
,encryptOptions
->envFile
);
914 SecArenaPoolFree(tmparena
, false);
917 // get the content info for the enveloped data
918 nlevels
= SecCmsMessageContentLevelCount(env_cmsg
);
919 for (i
= 0; i
< nlevels
; i
++)
922 cinfo
= SecCmsMessageContentLevel(env_cmsg
, i
);
923 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
924 if (typetag
== SEC_OID_PKCS7_DATA
)
926 // get the symmetric key
927 encryptOptions
->bulkalgtag
= SecCmsContentInfoGetContentEncAlgTag(cinfo
);
928 encryptOptions
->keysize
= SecCmsContentInfoGetBulkKeySize(cinfo
);
929 encryptOptions
->bulkkey
= SecCmsContentInfoGetBulkKey(cinfo
);
935 sec_error("could not retrieve enveloped data: messsage has: %ld levels", nlevels
);
939 SecCmsMessageDestroy(env_cmsg
);
944 static SecCmsMessageRef
encrypted_data(struct encryptOptionsStr
*encryptOptions
)
946 OSStatus rv
= paramErr
;
947 SecCmsMessageRef cmsg
= NULL
;
948 SecCmsContentInfoRef cinfo
;
949 SecCmsEncryptedDataRef encd
;
950 SecCmsEncoderRef ecx
= NULL
;
951 SecArenaPoolRef tmppoolp
= NULL
;
952 CSSM_DATA derOut
= { 0, };
954 /* arena for output */
955 SEC_CHECK(SecArenaPoolCreate(1024, &tmppoolp
), "failed to create arenapool");
956 // create the message object on its own pool
957 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
958 // build chain of objects: message->encryptedData->data
959 SEC_CHECK0(encd
= SecCmsEncryptedDataCreate(cmsg
, encryptOptions
->bulkalgtag
,
960 encryptOptions
->keysize
),
961 "cannot create CMS encryptedData object");
962 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
963 "message has no content info");
964 SEC_CHECK(SecCmsContentInfoSetContentEncryptedData(cmsg
, cinfo
, encd
),
965 "cannot attach CMS encryptedData object");
966 SEC_CHECK0(cinfo
= SecCmsEncryptedDataGetContentInfo(encd
),
967 "encrypted data has no content info");
968 /* we're always passing data in, so the content is NULL */
969 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
970 "cannot attach CMS data object");
971 SEC_CHECK(SecCmsEncoderCreate(cmsg
, NULL
, NULL
, &derOut
, tmppoolp
, NULL
, NULL
,
972 dkcb
, encryptOptions
->bulkkey
, NULL
, NULL
, &ecx
),
973 "cannot create encoder context");
974 SEC_CHECK(do_update((update_func
*)SecCmsEncoderUpdate
, ecx
, encryptOptions
->input
->Data
,
975 encryptOptions
->input
->Length
),
976 "failed to add data to encoder");
977 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encrypt data");
978 fwrite(derOut
.Data
, derOut
.Length
, 1, encryptOptions
->outfile
);
979 /* @@@ Check and report write errors. */
986 SecArenaPoolFree(tmppoolp
, false);
994 SecArenaPoolFree(tmppoolp
, false);
996 SecCmsMessageDestroy(cmsg
);
1001 static SecCmsMessageRef
signed_data_certsonly(struct certsonlyOptionsStr
*certsonlyOptions
)
1003 SecCmsMessageRef cmsg
= NULL
;
1004 SecCmsContentInfoRef cinfo
;
1005 SecCmsSignedDataRef sigd
;
1006 SecCertificateRef
*certs
= NULL
;
1007 SecKeychainRef dbhandle
;
1011 dbhandle
= certsonlyOptions
->options
->certDBHandle
;
1012 SEC_CHECK0(cnt
= nss_CMSArray_Count((void**)certsonlyOptions
->recipients
),
1013 "please indicate the nickname of a certificate to sign with");
1014 if ((certs
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
1016 sec_error("failed to alloc certs array: %s", strerror(errno
));
1019 for (i
=0; certsonlyOptions
->recipients
&& certsonlyOptions
->recipients
[i
] != NULL
; i
++)
1021 if ((certs
[i
] = CERT_FindCertByNicknameOrEmailAddr(dbhandle
,certsonlyOptions
->recipients
[i
])) == NULL
)
1029 // create the message object on its own pool
1030 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
1031 // build chain of objects: message->signedData->data
1032 SEC_CHECK0(sigd
= SecCmsSignedDataCreateCertsOnly(cmsg
, certs
[0], true),
1033 "cannot create certs only CMS signedData object");
1034 CFReleaseNull(certs
[0]);
1035 for (i
= 1; i
< cnt
; ++i
)
1037 SEC_CHECK2(SecCmsSignedDataAddCertChain(sigd
, certs
[i
]),
1038 "cannot add cert chain for \"%s\"", certsonlyOptions
->recipients
[i
]);
1039 CFReleaseNull(certs
[i
]);
1042 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
1043 "message has no content info");
1044 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
1045 "cannot attach CMS signedData object");
1046 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
1047 "signed data has no content info");
1048 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
1049 "cannot attach CMS data object");
1058 for (; i
< cnt
; ++i
)
1059 CFReleaseNull(certs
[i
]);
1063 if (cmsg
) SecCmsMessageDestroy(cmsg
);
1068 typedef enum { UNKNOWN
, DECODE
, SIGN
, ENCRYPT
, ENVELOPE
, CERTSONLY
} Mode
;
1070 int cms_util(int argc
, char * const *argv
)
1073 SecCmsMessageRef cmsg
= NULL
;
1076 Mode mode
= UNKNOWN
;
1077 PK11PasswordFunc pwcb
;
1079 struct decodeOptionsStr decodeOptions
= { 0 };
1080 struct signOptionsStr signOptions
= { 0 };
1081 struct envelopeOptionsStr envelopeOptions
= { 0 };
1082 struct certsonlyOptionsStr certsonlyOptions
= { 0 };
1083 struct encryptOptionsStr encryptOptions
= { 0 };
1084 struct optionsStr options
= { 0 };
1086 static char *ptrarray
[128] = { 0 };
1087 int nrecipients
= 0;
1090 const char *keychainName
= NULL
;
1091 CSSM_DATA input
= { 0,};
1092 CSSM_DATA output
= { 0,};
1093 CSSM_DATA dummy
= { 0, };
1094 CSSM_DATA envmsg
= { 0, };
1101 decodeOptions
.contentFile
= NULL
;
1102 decodeOptions
.suppressContent
= false;
1103 decodeOptions
.headerLevel
= -1;
1104 options
.certUsage
= certUsageEmailSigner
;
1105 options
.password
= NULL
;
1106 signOptions
.nickname
= NULL
;
1107 signOptions
.subjectKeyID
= NULL
;
1108 signOptions
.detached
= false;
1109 signOptions
.signingTime
= false;
1110 signOptions
.smimeProfile
= false;
1111 signOptions
.encryptionKeyPreferenceNick
= NULL
;
1112 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1113 envelopeOptions
.recipients
= NULL
;
1114 encryptOptions
.recipients
= NULL
;
1115 encryptOptions
.envmsg
= NULL
;
1116 encryptOptions
.envFile
= NULL
;
1117 encryptOptions
.bulkalgtag
= SEC_OID_UNKNOWN
;
1118 encryptOptions
.bulkkey
= NULL
;
1119 encryptOptions
.keysize
= -1;
1121 // Parse command line arguments
1122 while ((ch
= getopt(argc
, argv
, "CDEGH:N:OPSTY:Z:c:de:h:i:k:no:p:r:su:vt:")) != -1)
1137 sec_error("option -G only supported with option -S");
1138 result
= 2; /* Trigger usage message. */
1141 signOptions
.signingTime
= true;
1145 sec_error("option -n only supported with option -D");
1146 result
= 2; /* Trigger usage message. */
1153 decodeOptions
.suppressContent
= true;
1154 if (!strcmp(optarg
, "MD2"))
1155 signOptions
.hashAlgTag
= SEC_OID_MD2
;
1156 else if (!strcmp(optarg
, "MD4"))
1157 signOptions
.hashAlgTag
= SEC_OID_MD4
;
1158 else if (!strcmp(optarg
, "MD5"))
1159 signOptions
.hashAlgTag
= SEC_OID_MD5
;
1160 else if (!strcmp(optarg
, "SHA1"))
1161 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1162 else if (!strcmp(optarg
, "SHA256"))
1163 signOptions
.hashAlgTag
= SEC_OID_SHA256
;
1164 else if (!strcmp(optarg
, "SHA384"))
1165 signOptions
.hashAlgTag
= SEC_OID_SHA384
;
1166 else if (!strcmp(optarg
, "SHA512"))
1167 signOptions
.hashAlgTag
= SEC_OID_SHA512
;
1169 sec_error("option -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512");
1175 sec_error("option -N only supported with option -S");
1176 result
= 2; /* Trigger usage message. */
1179 signOptions
.nickname
= strdup(optarg
);
1186 sec_error("option -P only supported with option -S");
1187 result
= 2; /* Trigger usage message. */
1190 signOptions
.smimeProfile
= true;
1197 sec_error("option -T only supported with option -S");
1198 result
= 2; /* Trigger usage message. */
1201 signOptions
.detached
= true;
1205 sec_error("option -Y only supported with option -S");
1206 result
= 2; /* Trigger usage message. */
1209 signOptions
.encryptionKeyPreferenceNick
= strdup(optarg
);
1215 sec_error("option -c only supported with option -D");
1216 result
= 2; /* Trigger usage message. */
1219 if ((decodeOptions
.contentFile
= fopen(optarg
, "rb")) == NULL
)
1221 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1227 #ifdef HAVE_DODUMPSTATES
1231 #endif /* HAVE_DODUMPSTATES */
1234 envFileName
= strdup(optarg
);
1235 encryptOptions
.envFile
= fopen(envFileName
, "rb"); // PR_RDONLY, 00660);
1239 if (mode
!= DECODE
) {
1240 sec_error("option -h only supported with option -D");
1241 result
= 2; /* Trigger usage message. */
1244 decodeOptions
.headerLevel
= atoi(optarg
);
1245 if (decodeOptions
.headerLevel
< 0) {
1246 sec_error("option -h cannot have a negative value");
1251 inFile
= fopen(optarg
,"rb"); // PR_RDONLY, 00660);
1254 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1260 keychainName
= optarg
;
1266 sec_error("option -n only supported with option -D");
1267 result
= 2; /* Trigger usage message. */
1270 decodeOptions
.suppressContent
= true;
1273 outFile
= fopen(optarg
, "wb");
1274 if (outFile
== NULL
)
1276 sec_error("unable to open \"%s\" for writing: %s", optarg
, strerror(errno
));
1283 sec_error("option -p must have a value");
1284 result
= 2; /* Trigger usage message. */
1288 options
.password
= (PK11PasswordFunc
)ownpw
;//strdup(optarg);
1294 sec_error("option -r must have a value");
1295 result
= 2; /* Trigger usage message. */
1299 envelopeOptions
.recipients
= ptrarray
;
1300 str
= (char *)optarg
;
1302 tok
= strchr(str
, ',');
1303 if (tok
) *tok
= '\0';
1304 envelopeOptions
.recipients
[nrecipients
++] = strdup(str
);
1305 if (tok
) str
= tok
+ 1;
1307 envelopeOptions
.recipients
[nrecipients
] = NULL
;
1308 encryptOptions
.recipients
= envelopeOptions
.recipients
;
1309 certsonlyOptions
.recipients
= envelopeOptions
.recipients
;
1313 cms_update_single_byte
= 1;
1319 sec_error("option -Z must have a value");
1320 result
= 2; /* Trigger usage message. */
1323 signOptions
.subjectKeyID
= strdup(optarg
);
1329 int usageType
= atoi (optarg
);
1330 if (usageType
< certUsageSSLClient
|| usageType
> certUsageAnyCA
)
1335 options
.certUsage
= (SECCertUsage
)usageType
;
1343 signOptions
.timestampingURL
= strdup(optarg
);
1344 signOptions
.wantTimestamping
= true;
1347 result
= 2; /* Trigger usage message. */
1355 if (argc
!= 0 || mode
== UNKNOWN
)
1357 result
= 2; /* Trigger usage message. */
1363 if (mode
!= CERTSONLY
)
1364 SECU_FileToItem(&input
, inFile
);
1365 if (inFile
!= stdin
)
1368 fprintf(stderr
, "received commands\n");
1370 /* Call the libsec initialization routines */
1373 check_obsolete_keychain(keychainName
);
1374 options
.certDBHandle
= keychain_open(keychainName
);
1375 if (!options
.certDBHandle
)
1377 sec_perror("SecKeychainOpen", errSecInvalidKeychain
);
1384 fprintf(stderr
, "Got default certdb\n");
1389 decodeOptions
.options
= &options
;
1390 if (encryptOptions
.envFile
)
1392 /* Decoding encrypted-data, so get the bulkkey from an
1393 * enveloped-data message.
1395 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1396 decodeOptions
.options
= &options
;
1397 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
, &decodeOptions
);
1398 if (!encryptOptions
.envmsg
)
1400 sec_error("problem decoding env msg");
1404 rv
= get_enc_params(&encryptOptions
);
1405 decodeOptions
.dkcb
= dkcb
;
1406 decodeOptions
.bulkkey
= encryptOptions
.bulkkey
;
1408 cmsg
= decode(outFile
, &output
, &input
, &decodeOptions
);
1411 sec_error("problem decoding");
1414 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1417 signOptions
.options
= &options
;
1418 cmsg
= signed_data(&signOptions
);
1421 sec_error("problem signing");
1428 sec_error("you must specify an envelope file with -e");
1432 encryptOptions
.options
= &options
;
1433 encryptOptions
.input
= &input
;
1434 encryptOptions
.outfile
= outFile
;
1435 if (!encryptOptions
.envFile
) {
1436 encryptOptions
.envFile
= fopen(envFileName
,"wb"); //PR_WRONLY|PR_CREATE_FILE, 00660);
1437 if (!encryptOptions
.envFile
)
1439 sec_error("failed to create file %s: %s", envFileName
, strerror(errno
));
1446 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1447 decodeOptions
.options
= &options
;
1448 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
,
1450 if (encryptOptions
.envmsg
== NULL
)
1452 sec_error("problem decrypting env msg");
1458 /* decode an enveloped-data message to get the bulkkey (create
1459 * a new one if neccessary)
1461 rv
= get_enc_params(&encryptOptions
);
1462 /* create the encrypted-data message */
1463 cmsg
= encrypted_data(&encryptOptions
);
1466 sec_error("problem encrypting");
1470 if (encryptOptions
.bulkkey
)
1472 CFRelease(encryptOptions
.bulkkey
);
1473 encryptOptions
.bulkkey
= NULL
;
1477 envelopeOptions
.options
= &options
;
1478 cmsg
= enveloped_data(&envelopeOptions
);
1481 sec_error("problem enveloping");
1486 certsonlyOptions
.options
= &options
;
1487 cmsg
= signed_data_certsonly(&certsonlyOptions
);
1490 sec_error("problem with certs-only");
1495 /* Already handled above. */
1499 if ( (mode
== SIGN
|| mode
== ENVELOPE
|| mode
== CERTSONLY
)
1502 SecArenaPoolRef arena
= NULL
;
1503 SecCmsEncoderRef ecx
;
1504 CSSM_DATA output
= {};
1506 SEC_CHECK(SecArenaPoolCreate(1024, &arena
), "failed to create arenapool");
1507 pwcb
= (PK11PasswordFunc
)((options
.password
!= NULL
) ? ownpw
: NULL
);
1508 pwcb_arg
= (options
.password
!= NULL
) ? (void *)options
.password
: NULL
;
1510 fprintf(stderr
, "cmsg [%p]\n", cmsg
);
1511 fprintf(stderr
, "arena [%p]\n", arena
);
1513 fprintf(stderr
, "password [%s]\n", (char *)pwcb_arg
);
1515 fprintf(stderr
, "password [NULL]\n");
1518 SEC_CHECK(SecCmsEncoderCreate(cmsg
,
1519 NULL
, NULL
, /* DER output callback */
1520 &output
, arena
, /* destination storage */
1521 pwcb
, pwcb_arg
, /* password callback */
1522 NULL
, NULL
, /* decrypt key callback */
1523 NULL
, NULL
, /* detached digests */
1525 "cannot create encoder context");
1528 fprintf(stderr
, "input len [%ld]\n", input
.Length
);
1531 for (j
= 0; j
< input
.Length
; ++j
)
1532 fprintf(stderr
, "%2x%c", input
.Data
[j
], (j
>0&&j%35
==0)?'\n':' ');
1536 if (input
.Length
> 0) { /* skip if certs-only (or other zero content) */
1537 SEC_CHECK(SecCmsEncoderUpdate(ecx
, (char *)input
.Data
, input
.Length
),
1538 "failed to add data to encoder");
1541 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encode data");
1544 fprintf(stderr
, "encoding passed\n");
1547 /*PR_Write(output.data, output.len);*/
1548 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1550 fprintf(stderr
, "wrote to file\n");
1552 SecArenaPoolFree(arena
, false);
1556 if(signOptions
.encryptionKeyPreferenceNick
) {
1557 free(signOptions
.encryptionKeyPreferenceNick
);
1559 if(signOptions
.nickname
) {
1560 free(signOptions
.nickname
);
1562 if(signOptions
.subjectKeyID
) {
1563 free(signOptions
.subjectKeyID
);
1565 if(signOptions
.timestampingURL
) {
1566 free(signOptions
.timestampingURL
);
1572 SecCmsMessageDestroy(cmsg
);
1573 if (outFile
!= stdout
)
1576 if (decodeOptions
.contentFile
)
1577 fclose(decodeOptions
.contentFile
);
1583 #pragma mark ================ Misc from NSS ===================
1584 // from /security/nss/cmd/lib/secutil.c
1587 SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
)
1589 const int kReadSize
= 4096;
1590 size_t bytesRead
, totalRead
= 0;
1594 /* Make room in dst for the new data. */
1595 dst
->Length
+= kReadSize
;
1596 dst
->Data
= realloc(dst
->Data
, dst
->Length
);
1598 return 1 /* @@@ memFullErr */;
1600 bytesRead
= fread (&dst
->Data
[totalRead
], 1, kReadSize
, src
);
1601 totalRead
+= bytesRead
;
1602 } while (bytesRead
== kReadSize
);
1606 /* We are here, but there's no EOF. This is bad */
1612 return 1 /* @@@ ioErr */;
1615 /* Trim down the buffer. */
1616 dst
->Length
= totalRead
;
1617 dst
->Data
= realloc(dst
->Data
, totalRead
);
1619 return 1 /* @@@ memFullErr */;