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>
77 #include <Security/SecPolicyPriv.h>
78 // SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindBySubjectKeyID, SecCertificateFindByEmail
79 #include <Security/SecCertificatePriv.h>
80 // SecIdentitySearchCreateWithPolicy
81 #include <Security/SecIdentitySearchPriv.h>
83 #define SEC_CHECK0(CALL, ERROR) do { if (!(CALL)) { sec_error(ERROR); goto loser; } } while(0)
84 #define SEC_CHECK(CALL, ERROR) do { rv = (CALL); if (rv) { sec_perror(ERROR, rv); goto loser; } } while(0)
85 #define SEC_CHECK2(CALL, ERROR, ARG) do { rv = CALL; if (rv) \
86 { sec_error(ERROR ": %s", ARG, sec_errstr(rv)); goto loser; } } while(0)
91 static CSSM_KEYUSE
CERT_KeyUsageForCertUsage(SECCertUsage certUsage
)
95 case certUsageSSLClient
: return CSSM_KEYUSE_SIGN
;
96 case certUsageSSLServer
: return CSSM_KEYUSE_SIGN
;
97 case certUsageSSLServerWithStepUp
: return CSSM_KEYUSE_SIGN
;
98 case certUsageSSLCA
: return CSSM_KEYUSE_SIGN
;
99 case certUsageEmailSigner
: return CSSM_KEYUSE_SIGN
;
100 case certUsageEmailRecipient
: return CSSM_KEYUSE_UNWRAP
;
101 case certUsageObjectSigner
: return CSSM_KEYUSE_SIGN
;
102 case certUsageUserCertImport
: return CSSM_KEYUSE_SIGN
;
103 case certUsageVerifyCA
: return CSSM_KEYUSE_SIGN
;
104 case certUsageProtectedObjectSigner
: return CSSM_KEYUSE_SIGN
;
105 case certUsageStatusResponder
: return CSSM_KEYUSE_SIGN
;
106 case certUsageAnyCA
: return CSSM_KEYUSE_SIGN
;
108 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
109 return CSSM_KEYUSE_SIGN
;
113 static SecPolicyRef
CERT_PolicyForCertUsage(SECCertUsage certUsage
, const char *emailAddress
)
115 SecPolicyRef policy
= NULL
;
116 const CSSM_OID
*policyOID
;
121 case certUsageSSLClient
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
122 case certUsageSSLServer
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
123 case certUsageSSLServerWithStepUp
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
124 case certUsageSSLCA
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
125 case certUsageEmailSigner
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
126 case certUsageEmailRecipient
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
127 case certUsageObjectSigner
: policyOID
= &CSSMOID_APPLE_TP_CODE_SIGN
; break;
128 case certUsageUserCertImport
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
129 case certUsageVerifyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
130 case certUsageProtectedObjectSigner
: policyOID
= &CSSMOID_APPLE_ISIGN
; break;
131 case certUsageStatusResponder
: policyOID
= &CSSMOID_APPLE_TP_REVOCATION_OCSP
; break;
132 case certUsageAnyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
134 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
138 SEC_CHECK(SecPolicyCopy(CSSM_CERT_X_509v3
, policyOID
, &policy
), "SecPolicyCopy");
139 if (certUsage
== certUsageEmailSigner
|| certUsage
== certUsageEmailRecipient
)
141 CSSM_APPLE_TP_SMIME_OPTIONS options
=
143 CSSM_APPLE_TP_SMIME_OPTS_VERSION
,
144 certUsage
== certUsageEmailSigner
145 ? CE_KU_DigitalSignature
| CE_KU_NonRepudiation
146 : CE_KU_KeyEncipherment
,
147 emailAddress
? sizeof(emailAddress
) : 0,
150 CSSM_DATA value
= { sizeof(options
), (uint8
*)&options
};
151 SEC_CHECK(SecPolicySetValue(policy
, &value
), "SecPolicySetValue");
154 // @@@ Need to set values for SSL and other policies.
158 if (policy
) CFRelease(policy
);
162 static SecCertificateRef
CERT_FindUserCertByUsage(CFTypeRef keychainOrArray
, const char *emailAddress
,
163 SECCertUsage certUsage
, Boolean validOnly
)
165 SecKeychainSearchRef search
= NULL
;
166 SecCertificateRef cert
= NULL
;
170 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
174 SEC_CHECK2(SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &search
),
175 "create search for certificate with email: \"%s\"", emailAddress
);
178 SecKeychainItemRef item
;
179 rv
= SecKeychainSearchCopyNext(search
, &item
);
182 if (rv
== errSecItemNotFound
)
185 sec_perror("error finding next matching certificate", rv
);
189 cert
= (SecCertificateRef
)item
;
190 // @@@ Check cert against policy.
194 if (policy
) CFRelease(policy
);
195 if (search
) CFRelease(search
);
200 static SecIdentityRef
CERT_FindIdentityByUsage(CFTypeRef keychainOrArray
,
201 const char *emailAddress
,
202 SECCertUsage certUsage
,
205 SecIdentitySearchRef search
= NULL
;
206 SecIdentityRef identity
= NULL
;
207 CFStringRef idString
= CFStringCreateWithCString(NULL
, emailAddress
, kCFStringEncodingUTF8
);
211 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
216 SEC_CHECK2(SecIdentitySearchCreateWithPolicy(policy
, idString
,
217 CERT_KeyUsageForCertUsage(certUsage
), keychainOrArray
, validOnly
, &search
),
218 "create search for identity with email: \"%s\"", emailAddress
);
221 rv
= SecIdentitySearchCopyNext(search
, &identity
);
224 if (rv
== errSecItemNotFound
)
227 sec_perror("error finding next matching identity", rv
);
233 if (policy
) CFRelease(policy
);
234 if (search
) CFRelease(search
);
235 if (idString
) CFRelease(idString
);
241 SecIdentityRef identity
= NULL
;
242 SecCertificateRef cert
;
245 cert
= CERT_FindUserCertByUsage(keychainOrArray
, emailAddress
, certUsage
, validOnly
);
249 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, cert
, &identity
),
250 "failed to find private key for certificate with email: \"%s\"", emailAddress
);
252 if (cert
) CFRelease(cert
);
258 static SecCertificateRef
CERT_FindCertByNicknameOrEmailAddr(CFTypeRef keychainOrArray
, const char *emailAddress
)
260 SecCertificateRef certificate
= NULL
;
263 SEC_CHECK2(SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificate
),
264 "failed to find certificate with email: \"%s\"", emailAddress
);
270 static SecIdentityRef
CERT_FindIdentityBySubjectKeyID(CFTypeRef keychainOrArray
,
271 const char *subjectKeyIDString
)
273 // ss will be something like "B2ACD31AC8D0DA62E7679432ADDD3398EF66948B"
275 SecCertificateRef certificate
= NULL
;
276 SecIdentityRef identityRef
= NULL
;
279 CSSM_SIZE len
= strlen(subjectKeyIDString
)/2;
280 CSSM_DATA subjectKeyID
= {0,};
281 subjectKeyID
.Length
= len
;
282 subjectKeyID
.Data
= (uint8
*)malloc(subjectKeyID
.Length
);
283 fromHex(subjectKeyIDString
, &subjectKeyID
);
285 SEC_CHECK2(SecCertificateFindBySubjectKeyID(keychainOrArray
, &subjectKeyID
, &certificate
),
286 "failed to find identity with subject key ID: \"%s\"", subjectKeyIDString
);
288 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, certificate
, &identityRef
),
289 "failed to find certificate with subject key ID: \"%s\"", subjectKeyIDString
);
295 static OSStatus
CERT_CheckCertUsage (SecCertificateRef cert
,unsigned char usage
)
302 // @@@ Eleminate usage of this header.
304 //#include <security_asn1/secerr.h>
305 //#include "plgetopt.h"
306 //#include "secitem.h"
308 #ifdef HAVE_DODUMPSTATES
309 extern int doDumpStates
;
310 #endif /* HAVE_DODUMPSTATES */
312 OSStatus
SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
);
315 extern void SEC_Init(void); /* XXX */
316 static int cms_verbose
= 0;
317 static int cms_update_single_byte
= 0;
319 /* XXX stolen from cmsarray.c
320 * nss_CMSArray_Count - count number of elements in array
322 static int nss_CMSArray_Count(void **array
)
327 while (*array
++ != NULL
)
332 typedef OSStatus(update_func
)(void *cx
, const char *data
, size_t len
);
334 static OSStatus
do_update(update_func
*update
,
335 void *cx
, const unsigned char *data
, size_t len
)
338 if (cms_update_single_byte
)
340 for (;len
; --len
, ++data
)
342 rv
= update(cx
, (const char *)data
, 1);
348 rv
= update(cx
, (const char *)data
, len
);
354 static OSStatus
DigestFile(SecArenaPoolRef poolp
, CSSM_DATA
***digests
, CSSM_DATA
*input
, SECAlgorithmID
**algids
)
356 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(algids
);
360 do_update((update_func
*)SecCmsDigestContextUpdate
, digcx
, input
->Data
, input
->Length
);
362 return SecCmsDigestContextFinishMultiple(digcx
, poolp
, digests
);
366 ownpw(void *info
, Boolean retry
, void *arg
)
368 char * passwd
= NULL
;
370 if ( (!retry
) && arg
) {
371 passwd
= strdup((char *)arg
);
378 PK11PasswordFunc password
;
379 SECCertUsage certUsage
;
380 SecKeychainRef certDBHandle
;
383 struct decodeOptionsStr
{
384 struct optionsStr
*options
;
387 Boolean suppressContent
;
388 SecCmsGetDecryptKeyCallback dkcb
;
389 SecSymmetricKeyRef bulkkey
;
392 struct signOptionsStr
{
393 struct optionsStr
*options
;
395 char *encryptionKeyPreferenceNick
;
398 Boolean smimeProfile
;
400 SECOidTag hashAlgTag
;
401 Boolean wantTimestamping
;
402 char *timestampingURL
;
405 struct envelopeOptionsStr
{
406 struct optionsStr
*options
;
410 struct certsonlyOptionsStr
{
411 struct optionsStr
*options
;
415 struct encryptOptionsStr
{
416 struct optionsStr
*options
;
418 SecCmsMessageRef envmsg
;
422 SecSymmetricKeyRef bulkkey
;
423 SECOidTag bulkalgtag
;
427 static SecCmsMessageRef
decode(FILE *out
, CSSM_DATA
*output
, CSSM_DATA
*input
,
428 const struct decodeOptionsStr
*decodeOptions
)
430 SecCmsDecoderRef dcx
;
431 SecCmsMessageRef cmsg
=NULL
;
432 SecCmsContentInfoRef cinfo
;
433 SecCmsSignedDataRef sigd
= NULL
;
434 SecCmsEnvelopedDataRef envd
;
435 SecCmsEncryptedDataRef encd
;
436 SECAlgorithmID
**digestalgs
;
437 int nlevels
, i
, nsigners
, j
;
438 CFStringRef signercn
;
439 SecCmsSignerInfoRef si
;
442 SecArenaPoolRef poolp
= NULL
;
443 PK11PasswordFunc pwcb
;
445 CSSM_DATA
*item
, sitem
= { 0, };
446 CFTypeRef policy
= NULL
;
449 pwcb
= (PK11PasswordFunc
)((decodeOptions
->options
->password
!= NULL
) ? ownpw
: NULL
);
450 pwcb_arg
= (decodeOptions
->options
->password
!= NULL
) ?
451 (void *)decodeOptions
->options
->password
: NULL
;
453 if (decodeOptions
->contentFile
) // detached content: grab content file
454 SECU_FileToItem(&sitem
, decodeOptions
->contentFile
);
456 SEC_CHECK(SecCmsDecoderCreate(NULL
,
457 NULL
, NULL
, /* content callback */
458 pwcb
, pwcb_arg
, /* password callback */
459 decodeOptions
->dkcb
, /* decrypt key callback */
460 decodeOptions
->bulkkey
,
462 "failed to create to decoder");
463 SEC_CHECK(do_update((update_func
*)SecCmsDecoderUpdate
, dcx
, input
->Data
, input
->Length
),
464 "failed to add data to decoder");
465 SEC_CHECK(SecCmsDecoderFinish(dcx
, &cmsg
),
466 "failed to decode message");
468 if (decodeOptions
->headerLevel
>= 0)
470 /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
471 fprintf(out
, "SMIME: ");
474 nlevels
= SecCmsMessageContentLevelCount(cmsg
);
475 for (i
= 0; i
< nlevels
; i
++)
477 cinfo
= SecCmsMessageContentLevel(cmsg
, i
);
478 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
480 if (decodeOptions
->headerLevel
>= 0)
481 fprintf(out
, "\tlevel=%d.%d; ", decodeOptions
->headerLevel
, nlevels
- i
);
485 case SEC_OID_PKCS7_SIGNED_DATA
:
486 if (decodeOptions
->headerLevel
>= 0)
487 fprintf(out
, "type=signedData; ");
489 SEC_CHECK0(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
),
490 "problem finding signedData component");
491 /* if we have a content file, but no digests for this signedData */
492 if (decodeOptions
->contentFile
!= NULL
&& !SecCmsSignedDataHasDigests(sigd
))
494 SEC_CHECK(SecArenaPoolCreate(1024, &poolp
), "failed to create arenapool");
495 digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
496 SEC_CHECK(DigestFile(poolp
, &digests
, &sitem
, digestalgs
),
497 "problem computing message digest");
498 SEC_CHECK(SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
),
499 "problem setting message digests");
500 SecArenaPoolFree(poolp
, false);
503 policy
= CERT_PolicyForCertUsage(decodeOptions
->options
->certUsage
, NULL
);
504 // import the certificates
505 SEC_CHECK(SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
506 decodeOptions
->options
->certUsage
, true /* false */),
507 "cert import failed");
509 /* find out about signers */
510 nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
511 if (decodeOptions
->headerLevel
>= 0)
512 fprintf(out
, "nsigners=%d; ", nsigners
);
515 /* must be a cert transport message */
517 /* XXX workaround for bug #54014 */
518 SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
519 decodeOptions
->options
->certUsage
,true);
520 SEC_CHECK(SecCmsSignedDataVerifyCertsOnly(sigd
,decodeOptions
->options
->certDBHandle
, policy
),
521 "verify certs-only failed");
525 SEC_CHECK0(SecCmsSignedDataHasDigests(sigd
), "message has no digests");
526 for (j
= 0; j
< nsigners
; j
++)
528 si
= SecCmsSignedDataGetSignerInfo(sigd
, j
);
529 signercn
= SecCmsSignerInfoGetSignerCommonName(si
);
530 if (decodeOptions
->headerLevel
>= 0)
532 const char *px
= signercn
? CFStringGetCStringPtr(signercn
,kCFStringEncodingMacRoman
) : "<NULL>";
533 fprintf(out
, "\n\t\tsigner%d.id=\"%s\"; ", j
, px
);
535 SecCmsSignedDataVerifySignerInfo(sigd
, j
, decodeOptions
->options
->certDBHandle
,
537 if (decodeOptions
->headerLevel
>= 0)
538 fprintf(out
, "signer%d.status=%s; ", j
,
539 SecCmsUtilVerificationStatusToString(SecCmsSignerInfoGetVerificationStatus(si
)));
540 /* XXX what do we do if we don't print headers? */
543 case SEC_OID_PKCS7_ENVELOPED_DATA
:
544 if (decodeOptions
->headerLevel
>= 0)
545 fprintf(out
, "type=envelopedData; ");
546 envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
);
548 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
549 if (decodeOptions
->headerLevel
>= 0)
550 fprintf(out
, "type=encryptedData; ");
551 encd
= (SecCmsEncryptedDataRef
)SecCmsContentInfoGetContent(cinfo
);
553 case SEC_OID_PKCS7_DATA
:
554 if (decodeOptions
->headerLevel
>= 0)
555 fprintf(out
, "type=data; ");
560 if (decodeOptions
->headerLevel
>= 0)
564 if (!decodeOptions
->suppressContent
)
566 item
= decodeOptions
->contentFile
? &sitem
:
567 SecCmsMessageGetContent(cmsg
);
569 output
->Length
= item
->Length
;
570 output
->Data
= malloc(output
->Length
);
571 memcpy(output
->Data
, item
->Data
, output
->Length
);
574 if (policy
) CFRelease(policy
);
578 if (policy
) CFRelease(policy
);
579 if (cmsg
) SecCmsMessageDestroy(cmsg
);
583 /* example of a callback function to use with encoder */
586 writeout(void *arg, const char *buf, unsigned long len)
588 FILE *f = (FILE *)arg;
590 if (f != NULL && buf != NULL)
591 (void)fwrite(buf, len, 1, f);
595 static SecCmsMessageRef
signed_data(struct signOptionsStr
*signOptions
)
597 SecCmsMessageRef cmsg
= NULL
;
598 SecCmsContentInfoRef cinfo
;
599 SecCmsSignedDataRef sigd
;
600 SecCmsSignerInfoRef signerinfo
;
601 SecIdentityRef identity
= NULL
;
602 SecCertificateRef cert
= NULL
, ekpcert
= NULL
;
607 fprintf(stderr
, "Input to signed_data:\n");
608 if (signOptions
->options
->password
)
609 fprintf(stderr
, "password [%s]\n", "***" /*signOptions->options->password*/);
611 fprintf(stderr
, "password [NULL]\n");
612 fprintf(stderr
, "certUsage [%d]\n", signOptions
->options
->certUsage
);
613 if (signOptions
->options
->certDBHandle
)
614 fprintf(stderr
, "certdb [%p]\n", signOptions
->options
->certDBHandle
);
616 fprintf(stderr
, "certdb [NULL]\n");
617 if (signOptions
->nickname
)
618 fprintf(stderr
, "nickname [%s]\n", signOptions
->nickname
);
620 fprintf(stderr
, "nickname [NULL]\n");
621 if (signOptions
->subjectKeyID
)
622 fprintf(stderr
, "subject Key ID [%s]\n", signOptions
->subjectKeyID
);
625 if (signOptions
->subjectKeyID
)
627 if ((identity
= CERT_FindIdentityBySubjectKeyID(signOptions
->options
->certDBHandle
,
628 signOptions
->subjectKeyID
)) == NULL
)
630 sec_error("could not find signing identity for subject key ID: \"%s\"", signOptions
->subjectKeyID
);
635 fprintf(stderr
, "Found identity for subject key ID %s\n", signOptions
->subjectKeyID
);
637 else if (signOptions
->nickname
)
639 if ((identity
= CERT_FindIdentityByUsage(signOptions
->options
->certDBHandle
,
640 signOptions
->nickname
,
641 signOptions
->options
->certUsage
,
644 // look for identity by common name rather than email address
645 if ((identity
= find_identity(signOptions
->options
->certDBHandle
,
646 signOptions
->nickname
,
648 signOptions
->options
->certUsage
)) == NULL
)
650 sec_error("could not find signing identity for name: \"%s\"", signOptions
->nickname
);
656 fprintf(stderr
, "Found identity for %s\n", signOptions
->nickname
);
660 // no identity was specified
661 sec_error("no signing identity was specified");
665 // Get the cert from the identity
666 SEC_CHECK(SecIdentityCopyCertificate(identity
, &cert
),
667 "SecIdentityCopyCertificate");
668 // create the message object on its own pool
669 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
670 // build chain of objects: message->signedData->data
671 SEC_CHECK0(sigd
= SecCmsSignedDataCreate(cmsg
),
672 "cannot create CMS signedData object");
673 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
674 "message has no content info");
675 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
676 "cannot attach CMS signedData object");
677 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
678 "signed data has no content info");
679 /* we're always passing data in and detaching optionally */
680 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, signOptions
->detached
),
681 "cannot attach CMS data object");
682 // create & attach signer information
683 SEC_CHECK0(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, signOptions
->hashAlgTag
),
684 "cannot create CMS signerInfo object");
686 fprintf(stderr
,"Created CMS message, added signed data w/ signerinfo\n");
688 // we want the cert chain included for this one
689 SEC_CHECK(SecCmsSignerInfoIncludeCerts(signerinfo
, SecCmsCMCertChain
, signOptions
->options
->certUsage
),
690 "cannot add cert chain");
693 fprintf(stderr
, "imported certificate\n");
695 if (signOptions
->signingTime
)
696 SEC_CHECK(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()),
697 "cannot add signingTime attribute");
699 if (signOptions
->smimeProfile
)
700 SEC_CHECK(SecCmsSignerInfoAddSMIMECaps(signerinfo
),
701 "cannot add SMIMECaps attribute");
703 if (signOptions
->wantTimestamping
)
705 CFErrorRef error
= NULL
;
706 SecCmsMessageSetTSAContext(cmsg
, SecCmsTSAGetDefaultContext(&error
));
709 if (!signOptions
->encryptionKeyPreferenceNick
)
711 /* check signing cert for fitness as encryption cert */
712 OSStatus FitForEncrypt
= CERT_CheckCertUsage(cert
, certUsageEmailRecipient
);
714 if (noErr
== FitForEncrypt
)
716 /* if yes, add signing cert as EncryptionKeyPreference */
717 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
718 "cannot add default SMIMEEncKeyPrefs attribute");
719 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
720 "cannot add default MS SMIMEEncKeyPrefs attribute");
724 /* this is a dual-key cert case, we need to look for the encryption
725 certificate under the same nickname as the signing cert */
726 /* get the cert, add it to the message */
727 if ((ekpcert
= CERT_FindUserCertByUsage(
728 signOptions
->options
->certDBHandle
,
729 signOptions
->nickname
,
730 certUsageEmailRecipient
,
733 sec_error("can find encryption cert for \"%s\"", signOptions
->nickname
);
737 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
738 "cannot add SMIMEEncKeyPrefs attribute");
739 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
740 "cannot add MS SMIMEEncKeyPrefs attribute");
741 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
742 "cannot add encryption certificate");
745 else if (strcmp(signOptions
->encryptionKeyPreferenceNick
, "NONE") == 0)
751 /* specific email address for encryption preferred encryption cert specified.
752 get the cert, add it to the message */
753 if ((ekpcert
= CERT_FindUserCertByUsage(
754 signOptions
->options
->certDBHandle
,
755 signOptions
->encryptionKeyPreferenceNick
,
756 certUsageEmailRecipient
, false)) == NULL
)
758 sec_error("can find encryption cert for \"%s\"", signOptions
->encryptionKeyPreferenceNick
);
762 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
763 "cannot add SMIMEEncKeyPrefs attribute");
764 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
765 "cannot add MS SMIMEEncKeyPrefs attribute");
766 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
767 "cannot add encryption certificate");
770 SEC_CHECK(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
),
771 "cannot add CMS signerInfo object");
774 fprintf(stderr
, "created signed-data message\n");
776 if (ekpcert
) CFRelease(ekpcert
);
777 if (cert
) CFRelease(cert
);
778 if (identity
) CFRelease(identity
);
782 if (ekpcert
) CFRelease(ekpcert
);
783 if (cert
) CFRelease(cert
);
784 if (identity
) CFRelease(identity
);
785 SecCmsMessageDestroy(cmsg
);
789 static SecCmsMessageRef
enveloped_data(struct envelopeOptionsStr
*envelopeOptions
)
791 SecCmsMessageRef cmsg
= NULL
;
792 SecCmsContentInfoRef cinfo
;
793 SecCmsEnvelopedDataRef envd
;
794 SecCmsRecipientInfoRef recipientinfo
;
795 SecCertificateRef
*recipientcerts
= NULL
;
796 SecKeychainRef dbhandle
;
797 SECOidTag bulkalgtag
;
802 dbhandle
= envelopeOptions
->options
->certDBHandle
;
803 /* count the recipients */
804 SEC_CHECK0(cnt
= nss_CMSArray_Count((void **)envelopeOptions
->recipients
),
805 "please name at least one recipient");
807 // @@@ find the recipient's certs by email address or nickname
808 if ((recipientcerts
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
810 sec_error("failed to alloc certs array: %s", strerror(errno
));
814 for (i
= 0; envelopeOptions
->recipients
[i
] != NULL
; ++i
)
816 if ((recipientcerts
[i
] =
817 CERT_FindCertByNicknameOrEmailAddr(dbhandle
, envelopeOptions
->recipients
[i
])) == NULL
)
824 recipientcerts
[i
] = NULL
;
827 // find a nice bulk algorithm
828 SEC_CHECK(SecSMIMEFindBulkAlgForRecipients(recipientcerts
, &bulkalgtag
, &keysize
),
829 "cannot find common bulk algorithm");
830 // create the message object on its own pool
831 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
832 // build chain of objects: message->envelopedData->data
833 SEC_CHECK0(envd
= SecCmsEnvelopedDataCreate(cmsg
, bulkalgtag
, keysize
),
834 "cannot create CMS envelopedData object");
835 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
836 "message has no content info");
837 SEC_CHECK(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
),
838 "cannot attach CMS envelopedData object");
839 SEC_CHECK0(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
),
840 "enveloped data has no content info");
841 // We're always passing data in, so the content is NULL
842 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
843 "cannot attach CMS data object");
845 // create & attach recipient information
846 for (i
= 0; recipientcerts
[i
] != NULL
; i
++)
848 SEC_CHECK0(recipientinfo
= SecCmsRecipientInfoCreate(cmsg
, recipientcerts
[i
]),
849 "cannot create CMS recipientInfo object");
850 SEC_CHECK(SecCmsEnvelopedDataAddRecipient(envd
, recipientinfo
),
851 "cannot add CMS recipientInfo object");
852 CFRelease(recipientcerts
[i
]);
856 free(recipientcerts
);
862 for (; recipientcerts
[i
] != NULL
; i
++)
863 CFRelease(recipientcerts
[i
]);
867 SecCmsMessageDestroy(cmsg
);
870 free(recipientcerts
);
875 static SecSymmetricKeyRef
dkcb(void *arg
, SECAlgorithmID
*algid
)
877 return (SecSymmetricKeyRef
)arg
;
880 static OSStatus
get_enc_params(struct encryptOptionsStr
*encryptOptions
)
882 struct envelopeOptionsStr envelopeOptions
;
883 OSStatus rv
= paramErr
;
884 SecCmsMessageRef env_cmsg
= NULL
;
885 SecCmsContentInfoRef cinfo
;
888 // construct an enveloped data message to obtain bulk keys
889 if (encryptOptions
->envmsg
)
890 env_cmsg
= encryptOptions
->envmsg
; // get it from an old message
893 CSSM_DATA dummyOut
= { 0, };
894 CSSM_DATA dummyIn
= { 0, };
895 char str
[] = "Hello!";
896 SecArenaPoolRef tmparena
= NULL
;
898 SEC_CHECK(SecArenaPoolCreate(1024, &tmparena
), "failed to create arenapool");
900 dummyIn
.Data
= (unsigned char *)str
;
901 dummyIn
.Length
= strlen(str
);
902 envelopeOptions
.options
= encryptOptions
->options
;
903 envelopeOptions
.recipients
= encryptOptions
->recipients
;
904 env_cmsg
= enveloped_data(&envelopeOptions
);
905 SecCmsMessageEncode(env_cmsg
, &dummyIn
, tmparena
, &dummyOut
);
906 fwrite(dummyOut
.Data
, 1, dummyOut
.Length
,encryptOptions
->envFile
);
908 SecArenaPoolFree(tmparena
, false);
911 // get the content info for the enveloped data
912 nlevels
= SecCmsMessageContentLevelCount(env_cmsg
);
913 for (i
= 0; i
< nlevels
; i
++)
916 cinfo
= SecCmsMessageContentLevel(env_cmsg
, i
);
917 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
918 if (typetag
== SEC_OID_PKCS7_DATA
)
920 // get the symmetric key
921 encryptOptions
->bulkalgtag
= SecCmsContentInfoGetContentEncAlgTag(cinfo
);
922 encryptOptions
->keysize
= SecCmsContentInfoGetBulkKeySize(cinfo
);
923 encryptOptions
->bulkkey
= SecCmsContentInfoGetBulkKey(cinfo
);
929 sec_error("could not retrieve enveloped data: messsage has: %ld levels", nlevels
);
933 SecCmsMessageDestroy(env_cmsg
);
938 static SecCmsMessageRef
encrypted_data(struct encryptOptionsStr
*encryptOptions
)
940 OSStatus rv
= paramErr
;
941 SecCmsMessageRef cmsg
= NULL
;
942 SecCmsContentInfoRef cinfo
;
943 SecCmsEncryptedDataRef encd
;
944 SecCmsEncoderRef ecx
= NULL
;
945 SecArenaPoolRef tmppoolp
= NULL
;
946 CSSM_DATA derOut
= { 0, };
948 /* arena for output */
949 SEC_CHECK(SecArenaPoolCreate(1024, &tmppoolp
), "failed to create arenapool");
950 // create the message object on its own pool
951 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
952 // build chain of objects: message->encryptedData->data
953 SEC_CHECK0(encd
= SecCmsEncryptedDataCreate(cmsg
, encryptOptions
->bulkalgtag
,
954 encryptOptions
->keysize
),
955 "cannot create CMS encryptedData object");
956 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
957 "message has no content info");
958 SEC_CHECK(SecCmsContentInfoSetContentEncryptedData(cmsg
, cinfo
, encd
),
959 "cannot attach CMS encryptedData object");
960 SEC_CHECK0(cinfo
= SecCmsEncryptedDataGetContentInfo(encd
),
961 "encrypted data has no content info");
962 /* we're always passing data in, so the content is NULL */
963 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
964 "cannot attach CMS data object");
965 SEC_CHECK(SecCmsEncoderCreate(cmsg
, NULL
, NULL
, &derOut
, tmppoolp
, NULL
, NULL
,
966 dkcb
, encryptOptions
->bulkkey
, NULL
, NULL
, &ecx
),
967 "cannot create encoder context");
968 SEC_CHECK(do_update((update_func
*)SecCmsEncoderUpdate
, ecx
, encryptOptions
->input
->Data
,
969 encryptOptions
->input
->Length
),
970 "failed to add data to encoder");
971 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encrypt data");
972 fwrite(derOut
.Data
, derOut
.Length
, 1, encryptOptions
->outfile
);
973 /* @@@ Check and report write errors. */
980 SecArenaPoolFree(tmppoolp
, false);
988 SecArenaPoolFree(tmppoolp
, false);
990 SecCmsMessageDestroy(cmsg
);
995 static SecCmsMessageRef
signed_data_certsonly(struct certsonlyOptionsStr
*certsonlyOptions
)
997 SecCmsMessageRef cmsg
= NULL
;
998 SecCmsContentInfoRef cinfo
;
999 SecCmsSignedDataRef sigd
;
1000 SecCertificateRef
*certs
= NULL
;
1001 SecKeychainRef dbhandle
;
1005 dbhandle
= certsonlyOptions
->options
->certDBHandle
;
1006 SEC_CHECK0(cnt
= nss_CMSArray_Count((void**)certsonlyOptions
->recipients
),
1007 "please indicate the nickname of a certificate to sign with");
1008 if ((certs
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
1010 sec_error("failed to alloc certs array: %s", strerror(errno
));
1013 for (i
=0; certsonlyOptions
->recipients
&& certsonlyOptions
->recipients
[i
] != NULL
; i
++)
1015 if ((certs
[i
] = CERT_FindCertByNicknameOrEmailAddr(dbhandle
,certsonlyOptions
->recipients
[i
])) == NULL
)
1023 // create the message object on its own pool
1024 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
1025 // build chain of objects: message->signedData->data
1026 SEC_CHECK0(sigd
= SecCmsSignedDataCreateCertsOnly(cmsg
, certs
[0], true),
1027 "cannot create certs only CMS signedData object");
1028 CFRelease(certs
[0]);
1029 for (i
= 1; i
< cnt
; ++i
)
1031 SEC_CHECK2(SecCmsSignedDataAddCertChain(sigd
, certs
[i
]),
1032 "cannot add cert chain for \"%s\"", certsonlyOptions
->recipients
[i
]);
1033 CFRelease(certs
[i
]);
1036 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
1037 "message has no content info");
1038 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
1039 "cannot attach CMS signedData object");
1040 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
1041 "signed data has no content info");
1042 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
1043 "cannot attach CMS data object");
1052 for (; i
< cnt
; ++i
)
1053 CFRelease(certs
[i
]);
1057 if (cmsg
) SecCmsMessageDestroy(cmsg
);
1062 typedef enum { UNKNOWN
, DECODE
, SIGN
, ENCRYPT
, ENVELOPE
, CERTSONLY
} Mode
;
1064 int cms_util(int argc
, char * const *argv
)
1067 SecCmsMessageRef cmsg
= NULL
;
1070 Mode mode
= UNKNOWN
;
1071 PK11PasswordFunc pwcb
;
1073 struct decodeOptionsStr decodeOptions
= { 0 };
1074 struct signOptionsStr signOptions
= { 0 };
1075 struct envelopeOptionsStr envelopeOptions
= { 0 };
1076 struct certsonlyOptionsStr certsonlyOptions
= { 0 };
1077 struct encryptOptionsStr encryptOptions
= { 0 };
1078 struct optionsStr options
= { 0 };
1080 static char *ptrarray
[128] = { 0 };
1081 int nrecipients
= 0;
1084 const char *keychainName
= NULL
;
1085 CSSM_DATA input
= { 0,};
1086 CSSM_DATA output
= { 0,};
1087 CSSM_DATA dummy
= { 0, };
1088 CSSM_DATA envmsg
= { 0, };
1095 decodeOptions
.contentFile
= NULL
;
1096 decodeOptions
.suppressContent
= false;
1097 decodeOptions
.headerLevel
= -1;
1098 options
.certUsage
= certUsageEmailSigner
;
1099 options
.password
= NULL
;
1100 signOptions
.nickname
= NULL
;
1101 signOptions
.subjectKeyID
= NULL
;
1102 signOptions
.detached
= false;
1103 signOptions
.signingTime
= false;
1104 signOptions
.smimeProfile
= false;
1105 signOptions
.encryptionKeyPreferenceNick
= NULL
;
1106 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1107 envelopeOptions
.recipients
= NULL
;
1108 encryptOptions
.recipients
= NULL
;
1109 encryptOptions
.envmsg
= NULL
;
1110 encryptOptions
.envFile
= NULL
;
1111 encryptOptions
.bulkalgtag
= SEC_OID_UNKNOWN
;
1112 encryptOptions
.bulkkey
= NULL
;
1113 encryptOptions
.keysize
= -1;
1115 // Parse command line arguments
1116 while ((ch
= getopt(argc
, argv
, "CDEGH:N:OPSTY:Z:c:de:h:i:k:no:p:r:su:vt:")) != -1)
1131 sec_error("option -G only supported with option -S");
1132 result
= 2; /* Trigger usage message. */
1135 signOptions
.signingTime
= true;
1139 sec_error("option -n only supported with option -D");
1140 result
= 2; /* Trigger usage message. */
1143 decodeOptions
.suppressContent
= true;
1144 if (!strcmp(optarg
, "MD2"))
1145 signOptions
.hashAlgTag
= SEC_OID_MD2
;
1146 else if (!strcmp(optarg
, "MD4"))
1147 signOptions
.hashAlgTag
= SEC_OID_MD4
;
1148 else if (!strcmp(optarg
, "MD5"))
1149 signOptions
.hashAlgTag
= SEC_OID_MD5
;
1150 else if (!strcmp(optarg
, "SHA1"))
1151 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1152 else if (!strcmp(optarg
, "SHA256"))
1153 signOptions
.hashAlgTag
= SEC_OID_SHA256
;
1154 else if (!strcmp(optarg
, "SHA384"))
1155 signOptions
.hashAlgTag
= SEC_OID_SHA384
;
1156 else if (!strcmp(optarg
, "SHA512"))
1157 signOptions
.hashAlgTag
= SEC_OID_SHA512
;
1159 sec_error("option -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512");
1165 sec_error("option -N only supported with option -S");
1166 result
= 2; /* Trigger usage message. */
1169 signOptions
.nickname
= strdup(optarg
);
1176 sec_error("option -P only supported with option -S");
1177 result
= 2; /* Trigger usage message. */
1180 signOptions
.smimeProfile
= true;
1187 sec_error("option -T only supported with option -S");
1188 result
= 2; /* Trigger usage message. */
1191 signOptions
.detached
= true;
1195 sec_error("option -Y only supported with option -S");
1196 result
= 2; /* Trigger usage message. */
1199 signOptions
.encryptionKeyPreferenceNick
= strdup(optarg
);
1205 sec_error("option -c only supported with option -D");
1206 result
= 2; /* Trigger usage message. */
1209 if ((decodeOptions
.contentFile
= fopen(optarg
, "rb")) == NULL
)
1211 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1217 #ifdef HAVE_DODUMPSTATES
1221 #endif /* HAVE_DODUMPSTATES */
1224 envFileName
= strdup(optarg
);
1225 encryptOptions
.envFile
= fopen(envFileName
, "rb"); // PR_RDONLY, 00660);
1229 if (mode
!= DECODE
) {
1230 sec_error("option -h only supported with option -D");
1231 result
= 2; /* Trigger usage message. */
1234 decodeOptions
.headerLevel
= atoi(optarg
);
1235 if (decodeOptions
.headerLevel
< 0) {
1236 sec_error("option -h cannot have a negative value");
1241 inFile
= fopen(optarg
,"rb"); // PR_RDONLY, 00660);
1244 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1250 keychainName
= optarg
;
1256 sec_error("option -n only supported with option -D");
1257 result
= 2; /* Trigger usage message. */
1260 decodeOptions
.suppressContent
= true;
1263 outFile
= fopen(optarg
, "wb");
1264 if (outFile
== NULL
)
1266 sec_error("unable to open \"%s\" for writing: %s", optarg
, strerror(errno
));
1273 sec_error("option -p must have a value");
1274 result
= 2; /* Trigger usage message. */
1278 options
.password
= (PK11PasswordFunc
)ownpw
;//strdup(optarg);
1284 sec_error("option -r must have a value");
1285 result
= 2; /* Trigger usage message. */
1289 envelopeOptions
.recipients
= ptrarray
;
1290 str
= (char *)optarg
;
1292 tok
= strchr(str
, ',');
1293 if (tok
) *tok
= '\0';
1294 envelopeOptions
.recipients
[nrecipients
++] = strdup(str
);
1295 if (tok
) str
= tok
+ 1;
1297 envelopeOptions
.recipients
[nrecipients
] = NULL
;
1298 encryptOptions
.recipients
= envelopeOptions
.recipients
;
1299 certsonlyOptions
.recipients
= envelopeOptions
.recipients
;
1303 cms_update_single_byte
= 1;
1309 sec_error("option -Z must have a value");
1310 result
= 2; /* Trigger usage message. */
1313 signOptions
.subjectKeyID
= strdup(optarg
);
1319 int usageType
= atoi (strdup(optarg
));
1320 if (usageType
< certUsageSSLClient
|| usageType
> certUsageAnyCA
)
1325 options
.certUsage
= (SECCertUsage
)usageType
;
1333 signOptions
.timestampingURL
= strdup(optarg
);
1334 signOptions
.wantTimestamping
= true;
1337 result
= 2; /* Trigger usage message. */
1345 if (argc
!= 0 || mode
== UNKNOWN
)
1347 result
= 2; /* Trigger usage message. */
1353 if (mode
!= CERTSONLY
)
1354 SECU_FileToItem(&input
, inFile
);
1355 if (inFile
!= stdin
)
1358 fprintf(stderr
, "received commands\n");
1360 /* Call the libsec initialization routines */
1363 check_obsolete_keychain(keychainName
);
1364 options
.certDBHandle
= keychain_open(keychainName
);
1365 if (!options
.certDBHandle
)
1367 sec_perror("SecKeychainOpen", errSecInvalidKeychain
);
1374 fprintf(stderr
, "Got default certdb\n");
1379 decodeOptions
.options
= &options
;
1380 if (encryptOptions
.envFile
)
1382 /* Decoding encrypted-data, so get the bulkkey from an
1383 * enveloped-data message.
1385 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1386 decodeOptions
.options
= &options
;
1387 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
, &decodeOptions
);
1388 if (!encryptOptions
.envmsg
)
1390 sec_error("problem decoding env msg");
1394 rv
= get_enc_params(&encryptOptions
);
1395 decodeOptions
.dkcb
= dkcb
;
1396 decodeOptions
.bulkkey
= encryptOptions
.bulkkey
;
1398 cmsg
= decode(outFile
, &output
, &input
, &decodeOptions
);
1401 sec_error("problem decoding");
1404 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1407 signOptions
.options
= &options
;
1408 cmsg
= signed_data(&signOptions
);
1411 sec_error("problem signing");
1418 sec_error("you must specify an envelope file with -e");
1422 encryptOptions
.options
= &options
;
1423 encryptOptions
.input
= &input
;
1424 encryptOptions
.outfile
= outFile
;
1425 if (!encryptOptions
.envFile
) {
1426 encryptOptions
.envFile
= fopen(envFileName
,"wb"); //PR_WRONLY|PR_CREATE_FILE, 00660);
1427 if (!encryptOptions
.envFile
)
1429 sec_error("failed to create file %s: %s", envFileName
, strerror(errno
));
1436 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1437 decodeOptions
.options
= &options
;
1438 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
,
1440 if (encryptOptions
.envmsg
== NULL
)
1442 sec_error("problem decrypting env msg");
1448 /* decode an enveloped-data message to get the bulkkey (create
1449 * a new one if neccessary)
1451 rv
= get_enc_params(&encryptOptions
);
1452 /* create the encrypted-data message */
1453 cmsg
= encrypted_data(&encryptOptions
);
1456 sec_error("problem encrypting");
1460 if (encryptOptions
.bulkkey
)
1462 CFRelease(encryptOptions
.bulkkey
);
1463 encryptOptions
.bulkkey
= NULL
;
1467 envelopeOptions
.options
= &options
;
1468 cmsg
= enveloped_data(&envelopeOptions
);
1471 sec_error("problem enveloping");
1476 certsonlyOptions
.options
= &options
;
1477 cmsg
= signed_data_certsonly(&certsonlyOptions
);
1480 sec_error("problem with certs-only");
1485 /* Already handled above. */
1489 if ( (mode
== SIGN
|| mode
== ENVELOPE
|| mode
== CERTSONLY
)
1492 SecArenaPoolRef arena
= NULL
;
1493 SecCmsEncoderRef ecx
;
1494 CSSM_DATA output
= {};
1496 SEC_CHECK(SecArenaPoolCreate(1024, &arena
), "failed to create arenapool");
1497 pwcb
= (PK11PasswordFunc
)((options
.password
!= NULL
) ? ownpw
: NULL
);
1498 pwcb_arg
= (options
.password
!= NULL
) ? (void *)options
.password
: NULL
;
1500 fprintf(stderr
, "cmsg [%p]\n", cmsg
);
1501 fprintf(stderr
, "arena [%p]\n", arena
);
1503 fprintf(stderr
, "password [%s]\n", (char *)pwcb_arg
);
1505 fprintf(stderr
, "password [NULL]\n");
1508 SEC_CHECK(SecCmsEncoderCreate(cmsg
,
1509 NULL
, NULL
, /* DER output callback */
1510 &output
, arena
, /* destination storage */
1511 pwcb
, pwcb_arg
, /* password callback */
1512 NULL
, NULL
, /* decrypt key callback */
1513 NULL
, NULL
, /* detached digests */
1515 "cannot create encoder context");
1518 fprintf(stderr
, "input len [%ld]\n", input
.Length
);
1521 for (j
= 0; j
< input
.Length
; ++j
)
1522 fprintf(stderr
, "%2x%c", input
.Data
[j
], (j
>0&&j%35
==0)?'\n':' ');
1526 if (input
.Length
> 0) { /* skip if certs-only (or other zero content) */
1527 SEC_CHECK(SecCmsEncoderUpdate(ecx
, (char *)input
.Data
, input
.Length
),
1528 "failed to add data to encoder");
1531 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encode data");
1534 fprintf(stderr
, "encoding passed\n");
1537 /*PR_Write(output.data, output.len);*/
1538 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1540 fprintf(stderr
, "wrote to file\n");
1542 SecArenaPoolFree(arena
, false);
1547 SecCmsMessageDestroy(cmsg
);
1548 if (outFile
!= stdout
)
1551 if (decodeOptions
.contentFile
)
1552 fclose(decodeOptions
.contentFile
);
1558 #pragma mark ================ Misc from NSS ===================
1559 // from /security/nss/cmd/lib/secutil.c
1562 SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
)
1564 const int kReadSize
= 4096;
1565 size_t bytesRead
, totalRead
= 0;
1569 /* Make room in dst for the new data. */
1570 dst
->Length
+= kReadSize
;
1571 dst
->Data
= realloc(dst
->Data
, dst
->Length
);
1573 return 1 /* @@@ memFullErr */;
1575 bytesRead
= fread (&dst
->Data
[totalRead
], 1, kReadSize
, src
);
1576 totalRead
+= bytesRead
;
1577 } while (bytesRead
== kReadSize
);
1581 /* We are here, but there's no EOF. This is bad */
1587 return 1 /* @@@ ioErr */;
1590 /* Trim down the buffer. */
1591 dst
->Length
= totalRead
;
1592 dst
->Data
= realloc(dst
->Data
, totalRead
);
1594 return 1 /* @@@ memFullErr */;