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
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>
75 #include <Security/SecPolicyPriv.h>
76 // SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindBySubjectKeyID, SecCertificateFindByEmail
77 #include <Security/SecCertificatePriv.h>
78 // SecIdentitySearchCreateWithPolicy
79 #include <Security/SecIdentitySearchPriv.h>
81 #define SEC_CHECK0(CALL, ERROR) do { if (!(CALL)) { sec_error(ERROR); goto loser; } } while(0)
82 #define SEC_CHECK(CALL, ERROR) do { rv = (CALL); if (rv) { sec_perror(ERROR, rv); goto loser; } } while(0)
83 #define SEC_CHECK2(CALL, ERROR, ARG) do { rv = CALL; if (rv) \
84 { sec_error(ERROR ": %s", ARG, sec_errstr(rv)); goto loser; } } while(0)
89 static CSSM_KEYUSE
CERT_KeyUsageForCertUsage(SECCertUsage certUsage
)
93 case certUsageSSLClient
: return CSSM_KEYUSE_SIGN
;
94 case certUsageSSLServer
: return CSSM_KEYUSE_SIGN
;
95 case certUsageSSLServerWithStepUp
: return CSSM_KEYUSE_SIGN
;
96 case certUsageSSLCA
: return CSSM_KEYUSE_SIGN
;
97 case certUsageEmailSigner
: return CSSM_KEYUSE_SIGN
;
98 case certUsageEmailRecipient
: return CSSM_KEYUSE_UNWRAP
;
99 case certUsageObjectSigner
: return CSSM_KEYUSE_SIGN
;
100 case certUsageUserCertImport
: return CSSM_KEYUSE_SIGN
;
101 case certUsageVerifyCA
: return CSSM_KEYUSE_SIGN
;
102 case certUsageProtectedObjectSigner
: return CSSM_KEYUSE_SIGN
;
103 case certUsageStatusResponder
: return CSSM_KEYUSE_SIGN
;
104 case certUsageAnyCA
: return CSSM_KEYUSE_SIGN
;
106 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
107 return CSSM_KEYUSE_SIGN
;
111 static SecPolicyRef
CERT_PolicyForCertUsage(SECCertUsage certUsage
, const char *emailAddress
)
113 SecPolicyRef policy
= NULL
;
114 const CSSM_OID
*policyOID
;
119 case certUsageSSLClient
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
120 case certUsageSSLServer
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
121 case certUsageSSLServerWithStepUp
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
122 case certUsageSSLCA
: policyOID
= &CSSMOID_APPLE_TP_SSL
; break;
123 case certUsageEmailSigner
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
124 case certUsageEmailRecipient
: policyOID
= &CSSMOID_APPLE_TP_SMIME
; break;
125 case certUsageObjectSigner
: policyOID
= &CSSMOID_APPLE_TP_CODE_SIGN
; break;
126 case certUsageUserCertImport
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
127 case certUsageVerifyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
128 case certUsageProtectedObjectSigner
: policyOID
= &CSSMOID_APPLE_ISIGN
; break;
129 case certUsageStatusResponder
: policyOID
= &CSSMOID_APPLE_TP_REVOCATION_OCSP
; break;
130 case certUsageAnyCA
: policyOID
= &CSSMOID_APPLE_X509_BASIC
; break;
132 sec_error("CERT_PolicyForCertUsage %ld: unknown certUsage", certUsage
);
136 SEC_CHECK(SecPolicyCopy(CSSM_CERT_X_509v3
, policyOID
, &policy
), "SecPolicyCopy");
137 if (certUsage
== certUsageEmailSigner
|| certUsage
== certUsageEmailRecipient
)
139 CSSM_APPLE_TP_SMIME_OPTIONS options
=
141 CSSM_APPLE_TP_SMIME_OPTS_VERSION
,
142 certUsage
== certUsageEmailSigner
143 ? CE_KU_DigitalSignature
| CE_KU_NonRepudiation
144 : CE_KU_KeyEncipherment
,
145 emailAddress
? sizeof(emailAddress
) : 0,
148 CSSM_DATA value
= { sizeof(options
), (uint8
*)&options
};
149 SEC_CHECK(SecPolicySetValue(policy
, &value
), "SecPolicySetValue");
152 // @@@ Need to set values for SSL and other policies.
156 if (policy
) CFRelease(policy
);
160 static SecCertificateRef
CERT_FindUserCertByUsage(CFTypeRef keychainOrArray
, const char *emailAddress
,
161 SECCertUsage certUsage
, Boolean validOnly
)
163 SecKeychainSearchRef search
= NULL
;
164 SecCertificateRef cert
= NULL
;
168 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
172 SEC_CHECK2(SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &search
),
173 "create search for certificate with email: \"%s\"", emailAddress
);
176 SecKeychainItemRef item
;
177 rv
= SecKeychainSearchCopyNext(search
, &item
);
180 if (rv
== errSecItemNotFound
)
183 sec_perror("error finding next matching certificate", rv
);
187 cert
= (SecCertificateRef
)item
;
188 // @@@ Check cert against policy.
192 if (policy
) CFRelease(policy
);
193 if (search
) CFRelease(search
);
198 static SecIdentityRef
CERT_FindIdentityByUsage(CFTypeRef keychainOrArray
,
199 const char *emailAddress
,
200 SECCertUsage certUsage
,
203 SecIdentitySearchRef search
= NULL
;
204 SecIdentityRef identity
= NULL
;
205 CFStringRef idString
= CFStringCreateWithCString(NULL
, emailAddress
, kCFStringEncodingUTF8
);
209 policy
= CERT_PolicyForCertUsage(certUsage
, emailAddress
);
214 SEC_CHECK2(SecIdentitySearchCreateWithPolicy(policy
, idString
,
215 CERT_KeyUsageForCertUsage(certUsage
), keychainOrArray
, validOnly
, &search
),
216 "create search for identity with email: \"%s\"", emailAddress
);
219 rv
= SecIdentitySearchCopyNext(search
, &identity
);
222 if (rv
== errSecItemNotFound
)
225 sec_perror("error finding next matching identity", rv
);
231 if (policy
) CFRelease(policy
);
232 if (search
) CFRelease(search
);
233 if (idString
) CFRelease(idString
);
239 SecIdentityRef identity
= NULL
;
240 SecCertificateRef cert
;
243 cert
= CERT_FindUserCertByUsage(keychainOrArray
, emailAddress
, certUsage
, validOnly
);
247 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, cert
, &identity
),
248 "failed to find private key for certificate with email: \"%s\"", emailAddress
);
250 if (cert
) CFRelease(cert
);
256 static SecCertificateRef
CERT_FindCertByNicknameOrEmailAddr(CFTypeRef keychainOrArray
, const char *emailAddress
)
258 SecCertificateRef certificate
= NULL
;
261 SEC_CHECK2(SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificate
),
262 "failed to find certificate with email: \"%s\"", emailAddress
);
268 static SecIdentityRef
CERT_FindIdentityBySubjectKeyID(CFTypeRef keychainOrArray
,
269 const char *subjectKeyIDString
)
271 // ss will be something like "B2ACD31AC8D0DA62E7679432ADDD3398EF66948B"
273 SecCertificateRef certificate
= NULL
;
274 SecIdentityRef identityRef
= NULL
;
277 CSSM_SIZE len
= strlen(subjectKeyIDString
)/2;
278 CSSM_DATA subjectKeyID
= {0,};
279 subjectKeyID
.Length
= len
;
280 subjectKeyID
.Data
= (uint8
*)malloc(subjectKeyID
.Length
);
281 fromHex(subjectKeyIDString
, &subjectKeyID
);
283 SEC_CHECK2(SecCertificateFindBySubjectKeyID(keychainOrArray
, &subjectKeyID
, &certificate
),
284 "failed to find identity with subject key ID: \"%s\"", subjectKeyIDString
);
286 SEC_CHECK2(SecIdentityCreateWithCertificate(keychainOrArray
, certificate
, &identityRef
),
287 "failed to find certificate with subject key ID: \"%s\"", subjectKeyIDString
);
293 static OSStatus
CERT_CheckCertUsage (SecCertificateRef cert
,unsigned char usage
)
300 // @@@ Eleminate usage of this header.
302 //#include <security_asn1/secerr.h>
303 //#include "plgetopt.h"
304 //#include "secitem.h"
306 #ifdef HAVE_DODUMPSTATES
307 extern int doDumpStates
;
308 #endif /* HAVE_DODUMPSTATES */
310 OSStatus
SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
);
313 extern void SEC_Init(void); /* XXX */
314 static int cms_verbose
= 0;
315 static int cms_update_single_byte
= 0;
317 /* XXX stolen from cmsarray.c
318 * nss_CMSArray_Count - count number of elements in array
320 static int nss_CMSArray_Count(void **array
)
325 while (*array
++ != NULL
)
330 typedef OSStatus(update_func
)(void *cx
, const char *data
, unsigned int len
);
332 static OSStatus
do_update(update_func
*update
,
333 void *cx
, const unsigned char *data
, int len
)
336 if (cms_update_single_byte
)
338 for (;len
; --len
, ++data
)
340 rv
= update(cx
, (const char *)data
, 1);
346 rv
= update(cx
, (const char *)data
, len
);
352 static OSStatus
DigestFile(SecArenaPoolRef poolp
, CSSM_DATA
***digests
, CSSM_DATA
*input
, SECAlgorithmID
**algids
)
354 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(algids
);
358 do_update((update_func
*)SecCmsDigestContextUpdate
, digcx
, input
->Data
, input
->Length
);
360 return SecCmsDigestContextFinishMultiple(digcx
, poolp
, digests
);
364 ownpw(void *info
, Boolean retry
, void *arg
)
366 char * passwd
= NULL
;
368 if ( (!retry
) && arg
) {
369 passwd
= strdup((char *)arg
);
376 PK11PasswordFunc password
;
377 SECCertUsage certUsage
;
378 SecKeychainRef certDBHandle
;
381 struct decodeOptionsStr
{
382 struct optionsStr
*options
;
385 Boolean suppressContent
;
386 SecCmsGetDecryptKeyCallback dkcb
;
387 SecSymmetricKeyRef bulkkey
;
390 struct signOptionsStr
{
391 struct optionsStr
*options
;
393 char *encryptionKeyPreferenceNick
;
396 Boolean smimeProfile
;
398 SECOidTag hashAlgTag
;
399 Boolean wantTimestamping
;
400 char *timestampingURL
;
403 struct envelopeOptionsStr
{
404 struct optionsStr
*options
;
408 struct certsonlyOptionsStr
{
409 struct optionsStr
*options
;
413 struct encryptOptionsStr
{
414 struct optionsStr
*options
;
416 SecCmsMessageRef envmsg
;
420 SecSymmetricKeyRef bulkkey
;
421 SECOidTag bulkalgtag
;
425 static SecCmsMessageRef
decode(FILE *out
, CSSM_DATA
*output
, CSSM_DATA
*input
,
426 const struct decodeOptionsStr
*decodeOptions
)
428 SecCmsDecoderRef dcx
;
429 SecCmsMessageRef cmsg
=NULL
;
430 SecCmsContentInfoRef cinfo
;
431 SecCmsSignedDataRef sigd
= NULL
;
432 SecCmsEnvelopedDataRef envd
;
433 SecCmsEncryptedDataRef encd
;
434 SECAlgorithmID
**digestalgs
;
435 int nlevels
, i
, nsigners
, j
;
436 CFStringRef signercn
;
437 SecCmsSignerInfoRef si
;
440 SecArenaPoolRef poolp
= NULL
;
441 PK11PasswordFunc pwcb
;
443 CSSM_DATA
*item
, sitem
= { 0, };
444 CFTypeRef policy
= NULL
;
447 pwcb
= (PK11PasswordFunc
)((decodeOptions
->options
->password
!= NULL
) ? ownpw
: NULL
);
448 pwcb_arg
= (decodeOptions
->options
->password
!= NULL
) ?
449 (void *)decodeOptions
->options
->password
: NULL
;
451 if (decodeOptions
->contentFile
) // detached content: grab content file
452 SECU_FileToItem(&sitem
, decodeOptions
->contentFile
);
454 SEC_CHECK(SecCmsDecoderCreate(NULL
,
455 NULL
, NULL
, /* content callback */
456 pwcb
, pwcb_arg
, /* password callback */
457 decodeOptions
->dkcb
, /* decrypt key callback */
458 decodeOptions
->bulkkey
,
460 "failed to create to decoder");
461 SEC_CHECK(do_update((update_func
*)SecCmsDecoderUpdate
, dcx
, input
->Data
, input
->Length
),
462 "failed to add data to decoder");
463 SEC_CHECK(SecCmsDecoderFinish(dcx
, &cmsg
),
464 "failed to decode message");
466 if (decodeOptions
->headerLevel
>= 0)
468 /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
469 fprintf(out
, "SMIME: ");
472 nlevels
= SecCmsMessageContentLevelCount(cmsg
);
473 for (i
= 0; i
< nlevels
; i
++)
475 cinfo
= SecCmsMessageContentLevel(cmsg
, i
);
476 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
478 if (decodeOptions
->headerLevel
>= 0)
479 fprintf(out
, "\tlevel=%d.%d; ", decodeOptions
->headerLevel
, nlevels
- i
);
483 case SEC_OID_PKCS7_SIGNED_DATA
:
484 if (decodeOptions
->headerLevel
>= 0)
485 fprintf(out
, "type=signedData; ");
487 SEC_CHECK0(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
),
488 "problem finding signedData component");
489 /* if we have a content file, but no digests for this signedData */
490 if (decodeOptions
->contentFile
!= NULL
&& !SecCmsSignedDataHasDigests(sigd
))
492 SEC_CHECK(SecArenaPoolCreate(1024, &poolp
), "failed to create arenapool");
493 digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
494 SEC_CHECK(DigestFile(poolp
, &digests
, &sitem
, digestalgs
),
495 "problem computing message digest");
496 SEC_CHECK(SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
),
497 "problem setting message digests");
498 SecArenaPoolFree(poolp
, false);
501 policy
= CERT_PolicyForCertUsage(decodeOptions
->options
->certUsage
, NULL
);
502 // import the certificates
503 SEC_CHECK(SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
504 decodeOptions
->options
->certUsage
, true /* false */),
505 "cert import failed");
507 /* find out about signers */
508 nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
509 if (decodeOptions
->headerLevel
>= 0)
510 fprintf(out
, "nsigners=%d; ", nsigners
);
513 /* must be a cert transport message */
515 /* XXX workaround for bug #54014 */
516 SecCmsSignedDataImportCerts(sigd
,decodeOptions
->options
->certDBHandle
,
517 decodeOptions
->options
->certUsage
,true);
518 SEC_CHECK(SecCmsSignedDataVerifyCertsOnly(sigd
,decodeOptions
->options
->certDBHandle
, policy
),
519 "verify certs-only failed");
523 SEC_CHECK0(SecCmsSignedDataHasDigests(sigd
), "message has no digests");
524 for (j
= 0; j
< nsigners
; j
++)
526 si
= SecCmsSignedDataGetSignerInfo(sigd
, j
);
527 signercn
= SecCmsSignerInfoGetSignerCommonName(si
);
528 if (decodeOptions
->headerLevel
>= 0)
530 const char *px
= signercn
? CFStringGetCStringPtr(signercn
,kCFStringEncodingMacRoman
) : "<NULL>";
531 fprintf(out
, "\n\t\tsigner%d.id=\"%s\"; ", j
, px
);
533 SecCmsSignedDataVerifySignerInfo(sigd
, j
, decodeOptions
->options
->certDBHandle
,
535 if (decodeOptions
->headerLevel
>= 0)
536 fprintf(out
, "signer%d.status=%s; ", j
,
537 SecCmsUtilVerificationStatusToString(SecCmsSignerInfoGetVerificationStatus(si
)));
538 /* XXX what do we do if we don't print headers? */
541 case SEC_OID_PKCS7_ENVELOPED_DATA
:
542 if (decodeOptions
->headerLevel
>= 0)
543 fprintf(out
, "type=envelopedData; ");
544 envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
);
546 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
547 if (decodeOptions
->headerLevel
>= 0)
548 fprintf(out
, "type=encryptedData; ");
549 encd
= (SecCmsEncryptedDataRef
)SecCmsContentInfoGetContent(cinfo
);
551 case SEC_OID_PKCS7_DATA
:
552 if (decodeOptions
->headerLevel
>= 0)
553 fprintf(out
, "type=data; ");
558 if (decodeOptions
->headerLevel
>= 0)
562 if (!decodeOptions
->suppressContent
)
564 item
= decodeOptions
->contentFile
? &sitem
:
565 SecCmsMessageGetContent(cmsg
);
567 output
->Length
= item
->Length
;
568 output
->Data
= malloc(output
->Length
);
569 memcpy(output
->Data
, item
->Data
, output
->Length
);
572 if (policy
) CFRelease(policy
);
576 if (policy
) CFRelease(policy
);
577 if (cmsg
) SecCmsMessageDestroy(cmsg
);
581 /* example of a callback function to use with encoder */
584 writeout(void *arg, const char *buf, unsigned long len)
586 FILE *f = (FILE *)arg;
588 if (f != NULL && buf != NULL)
589 (void)fwrite(buf, len, 1, f);
593 static SecCmsMessageRef
signed_data(struct signOptionsStr
*signOptions
)
595 SecCmsMessageRef cmsg
= NULL
;
596 SecCmsContentInfoRef cinfo
;
597 SecCmsSignedDataRef sigd
;
598 SecCmsSignerInfoRef signerinfo
;
599 SecIdentityRef identity
= NULL
;
600 SecCertificateRef cert
= NULL
, ekpcert
= NULL
;
605 fprintf(stderr
, "Input to signed_data:\n");
606 if (signOptions
->options
->password
)
607 fprintf(stderr
, "password [%s]\n", "***" /*signOptions->options->password*/);
609 fprintf(stderr
, "password [NULL]\n");
610 fprintf(stderr
, "certUsage [%d]\n", signOptions
->options
->certUsage
);
611 if (signOptions
->options
->certDBHandle
)
612 fprintf(stderr
, "certdb [%p]\n", signOptions
->options
->certDBHandle
);
614 fprintf(stderr
, "certdb [NULL]\n");
615 if (signOptions
->nickname
)
616 fprintf(stderr
, "nickname [%s]\n", signOptions
->nickname
);
618 fprintf(stderr
, "nickname [NULL]\n");
619 if (signOptions
->subjectKeyID
)
620 fprintf(stderr
, "subject Key ID [%s]\n", signOptions
->subjectKeyID
);
623 if (signOptions
->subjectKeyID
)
625 if ((identity
= CERT_FindIdentityBySubjectKeyID(signOptions
->options
->certDBHandle
,
626 signOptions
->subjectKeyID
)) == NULL
)
628 sec_error("could not find signing identity for subject key ID: \"%s\"", signOptions
->subjectKeyID
);
633 fprintf(stderr
, "Found identity for subject key ID %s\n", signOptions
->subjectKeyID
);
635 else if (signOptions
->nickname
)
637 if ((identity
= CERT_FindIdentityByUsage(signOptions
->options
->certDBHandle
,
638 signOptions
->nickname
,
639 signOptions
->options
->certUsage
,
642 // look for identity by common name rather than email address
643 if ((identity
= find_identity(signOptions
->options
->certDBHandle
,
644 signOptions
->nickname
,
646 signOptions
->options
->certUsage
)) == NULL
)
648 sec_error("could not find signing identity for name: \"%s\"", signOptions
->nickname
);
654 fprintf(stderr
, "Found identity for %s\n", signOptions
->nickname
);
658 // no identity was specified
659 sec_error("no signing identity was specified");
663 // Get the cert from the identity
664 SEC_CHECK(SecIdentityCopyCertificate(identity
, &cert
),
665 "SecIdentityCopyCertificate");
666 // create the message object on its own pool
667 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
668 // build chain of objects: message->signedData->data
669 SEC_CHECK0(sigd
= SecCmsSignedDataCreate(cmsg
),
670 "cannot create CMS signedData object");
671 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
672 "message has no content info");
673 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
674 "cannot attach CMS signedData object");
675 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
676 "signed data has no content info");
677 /* we're always passing data in and detaching optionally */
678 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, signOptions
->detached
),
679 "cannot attach CMS data object");
680 // create & attach signer information
681 SEC_CHECK0(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, signOptions
->hashAlgTag
),
682 "cannot create CMS signerInfo object");
684 fprintf(stderr
,"Created CMS message, added signed data w/ signerinfo\n");
686 // we want the cert chain included for this one
687 SEC_CHECK(SecCmsSignerInfoIncludeCerts(signerinfo
, SecCmsCMCertChain
, signOptions
->options
->certUsage
),
688 "cannot add cert chain");
691 fprintf(stderr
, "imported certificate\n");
693 if (signOptions
->signingTime
)
694 SEC_CHECK(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()),
695 "cannot add signingTime attribute");
697 if (signOptions
->smimeProfile
)
698 SEC_CHECK(SecCmsSignerInfoAddSMIMECaps(signerinfo
),
699 "cannot add SMIMECaps attribute");
701 if (signOptions
->wantTimestamping
)
703 CFErrorRef error
= NULL
;
704 SecCmsMessageSetTSAContext(cmsg
, SecCmsTSAGetDefaultContext(&error
));
707 if (!signOptions
->encryptionKeyPreferenceNick
)
709 /* check signing cert for fitness as encryption cert */
710 OSStatus FitForEncrypt
= CERT_CheckCertUsage(cert
, certUsageEmailRecipient
);
712 if (noErr
== FitForEncrypt
)
714 /* if yes, add signing cert as EncryptionKeyPreference */
715 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
716 "cannot add default SMIMEEncKeyPrefs attribute");
717 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, cert
, signOptions
->options
->certDBHandle
),
718 "cannot add default MS SMIMEEncKeyPrefs attribute");
722 /* this is a dual-key cert case, we need to look for the encryption
723 certificate under the same nickname as the signing cert */
724 /* get the cert, add it to the message */
725 if ((ekpcert
= CERT_FindUserCertByUsage(
726 signOptions
->options
->certDBHandle
,
727 signOptions
->nickname
,
728 certUsageEmailRecipient
,
731 sec_error("can find encryption cert for \"%s\"", signOptions
->nickname
);
735 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
736 "cannot add SMIMEEncKeyPrefs attribute");
737 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
738 "cannot add MS SMIMEEncKeyPrefs attribute");
739 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
740 "cannot add encryption certificate");
743 else if (strcmp(signOptions
->encryptionKeyPreferenceNick
, "NONE") == 0)
749 /* specific email address for encryption preferred encryption cert specified.
750 get the cert, add it to the message */
751 if ((ekpcert
= CERT_FindUserCertByUsage(
752 signOptions
->options
->certDBHandle
,
753 signOptions
->encryptionKeyPreferenceNick
,
754 certUsageEmailRecipient
, false)) == NULL
)
756 sec_error("can find encryption cert for \"%s\"", signOptions
->encryptionKeyPreferenceNick
);
760 SEC_CHECK(SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
761 "cannot add SMIMEEncKeyPrefs attribute");
762 SEC_CHECK(SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,signOptions
->options
->certDBHandle
),
763 "cannot add MS SMIMEEncKeyPrefs attribute");
764 SEC_CHECK(SecCmsSignedDataAddCertificate(sigd
, ekpcert
),
765 "cannot add encryption certificate");
768 SEC_CHECK(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
),
769 "cannot add CMS signerInfo object");
772 fprintf(stderr
, "created signed-data message\n");
774 if (ekpcert
) CFRelease(ekpcert
);
775 if (cert
) CFRelease(cert
);
776 if (identity
) CFRelease(identity
);
780 if (ekpcert
) CFRelease(ekpcert
);
781 if (cert
) CFRelease(cert
);
782 if (identity
) CFRelease(identity
);
783 SecCmsMessageDestroy(cmsg
);
787 static SecCmsMessageRef
enveloped_data(struct envelopeOptionsStr
*envelopeOptions
)
789 SecCmsMessageRef cmsg
= NULL
;
790 SecCmsContentInfoRef cinfo
;
791 SecCmsEnvelopedDataRef envd
;
792 SecCmsRecipientInfoRef recipientinfo
;
793 SecCertificateRef
*recipientcerts
= NULL
;
794 SecKeychainRef dbhandle
;
795 SECOidTag bulkalgtag
;
800 dbhandle
= envelopeOptions
->options
->certDBHandle
;
801 /* count the recipients */
802 SEC_CHECK0(cnt
= nss_CMSArray_Count((void **)envelopeOptions
->recipients
),
803 "please name at least one recipient");
805 // @@@ find the recipient's certs by email address or nickname
806 if ((recipientcerts
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
808 sec_error("failed to alloc certs array: %s", strerror(errno
));
812 for (i
= 0; envelopeOptions
->recipients
[i
] != NULL
; ++i
)
814 if ((recipientcerts
[i
] =
815 CERT_FindCertByNicknameOrEmailAddr(dbhandle
, envelopeOptions
->recipients
[i
])) == NULL
)
822 recipientcerts
[i
] = NULL
;
825 // find a nice bulk algorithm
826 SEC_CHECK(SecSMIMEFindBulkAlgForRecipients(recipientcerts
, &bulkalgtag
, &keysize
),
827 "cannot find common bulk algorithm");
828 // create the message object on its own pool
829 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
830 // build chain of objects: message->envelopedData->data
831 SEC_CHECK0(envd
= SecCmsEnvelopedDataCreate(cmsg
, bulkalgtag
, keysize
),
832 "cannot create CMS envelopedData object");
833 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
834 "message has no content info");
835 SEC_CHECK(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
),
836 "cannot attach CMS envelopedData object");
837 SEC_CHECK0(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
),
838 "enveloped data has no content info");
839 // We're always passing data in, so the content is NULL
840 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
841 "cannot attach CMS data object");
843 // create & attach recipient information
844 for (i
= 0; recipientcerts
[i
] != NULL
; i
++)
846 SEC_CHECK0(recipientinfo
= SecCmsRecipientInfoCreate(cmsg
, recipientcerts
[i
]),
847 "cannot create CMS recipientInfo object");
848 SEC_CHECK(SecCmsEnvelopedDataAddRecipient(envd
, recipientinfo
),
849 "cannot add CMS recipientInfo object");
850 CFRelease(recipientcerts
[i
]);
854 free(recipientcerts
);
860 for (; recipientcerts
[i
] != NULL
; i
++)
861 CFRelease(recipientcerts
[i
]);
865 SecCmsMessageDestroy(cmsg
);
868 free(recipientcerts
);
873 static SecSymmetricKeyRef
dkcb(void *arg
, SECAlgorithmID
*algid
)
875 return (SecSymmetricKeyRef
)arg
;
878 static OSStatus
get_enc_params(struct encryptOptionsStr
*encryptOptions
)
880 struct envelopeOptionsStr envelopeOptions
;
881 OSStatus rv
= paramErr
;
882 SecCmsMessageRef env_cmsg
= NULL
;
883 SecCmsContentInfoRef cinfo
;
886 // construct an enveloped data message to obtain bulk keys
887 if (encryptOptions
->envmsg
)
888 env_cmsg
= encryptOptions
->envmsg
; // get it from an old message
891 CSSM_DATA dummyOut
= { 0, };
892 CSSM_DATA dummyIn
= { 0, };
893 char str
[] = "Hello!";
894 SecArenaPoolRef tmparena
= NULL
;
896 SEC_CHECK(SecArenaPoolCreate(1024, &tmparena
), "failed to create arenapool");
898 dummyIn
.Data
= (unsigned char *)str
;
899 dummyIn
.Length
= strlen(str
);
900 envelopeOptions
.options
= encryptOptions
->options
;
901 envelopeOptions
.recipients
= encryptOptions
->recipients
;
902 env_cmsg
= enveloped_data(&envelopeOptions
);
903 SecCmsMessageEncode(env_cmsg
, &dummyIn
, tmparena
, &dummyOut
);
904 fwrite(dummyOut
.Data
, 1, dummyOut
.Length
,encryptOptions
->envFile
);
906 SecArenaPoolFree(tmparena
, false);
909 // get the content info for the enveloped data
910 nlevels
= SecCmsMessageContentLevelCount(env_cmsg
);
911 for (i
= 0; i
< nlevels
; i
++)
914 cinfo
= SecCmsMessageContentLevel(env_cmsg
, i
);
915 typetag
= SecCmsContentInfoGetContentTypeTag(cinfo
);
916 if (typetag
== SEC_OID_PKCS7_DATA
)
918 // get the symmetric key
919 encryptOptions
->bulkalgtag
= SecCmsContentInfoGetContentEncAlgTag(cinfo
);
920 encryptOptions
->keysize
= SecCmsContentInfoGetBulkKeySize(cinfo
);
921 encryptOptions
->bulkkey
= SecCmsContentInfoGetBulkKey(cinfo
);
927 sec_error("could not retrieve enveloped data: messsage has: %ld levels", nlevels
);
931 SecCmsMessageDestroy(env_cmsg
);
936 static SecCmsMessageRef
encrypted_data(struct encryptOptionsStr
*encryptOptions
)
938 OSStatus rv
= paramErr
;
939 SecCmsMessageRef cmsg
= NULL
;
940 SecCmsContentInfoRef cinfo
;
941 SecCmsEncryptedDataRef encd
;
942 SecCmsEncoderRef ecx
= NULL
;
943 SecArenaPoolRef tmppoolp
= NULL
;
944 CSSM_DATA derOut
= { 0, };
946 /* arena for output */
947 SEC_CHECK(SecArenaPoolCreate(1024, &tmppoolp
), "failed to create arenapool");
948 // create the message object on its own pool
949 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
950 // build chain of objects: message->encryptedData->data
951 SEC_CHECK0(encd
= SecCmsEncryptedDataCreate(cmsg
, encryptOptions
->bulkalgtag
,
952 encryptOptions
->keysize
),
953 "cannot create CMS encryptedData object");
954 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
955 "message has no content info");
956 SEC_CHECK(SecCmsContentInfoSetContentEncryptedData(cmsg
, cinfo
, encd
),
957 "cannot attach CMS encryptedData object");
958 SEC_CHECK0(cinfo
= SecCmsEncryptedDataGetContentInfo(encd
),
959 "encrypted data has no content info");
960 /* we're always passing data in, so the content is NULL */
961 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
962 "cannot attach CMS data object");
963 SEC_CHECK(SecCmsEncoderCreate(cmsg
, NULL
, NULL
, &derOut
, tmppoolp
, NULL
, NULL
,
964 dkcb
, encryptOptions
->bulkkey
, NULL
, NULL
, &ecx
),
965 "cannot create encoder context");
966 SEC_CHECK(do_update((update_func
*)SecCmsEncoderUpdate
, ecx
, encryptOptions
->input
->Data
,
967 encryptOptions
->input
->Length
),
968 "failed to add data to encoder");
969 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encrypt data");
970 fwrite(derOut
.Data
, derOut
.Length
, 1, encryptOptions
->outfile
);
971 /* @@@ Check and report write errors. */
978 SecArenaPoolFree(tmppoolp
, false);
986 SecArenaPoolFree(tmppoolp
, false);
988 SecCmsMessageDestroy(cmsg
);
993 static SecCmsMessageRef
signed_data_certsonly(struct certsonlyOptionsStr
*certsonlyOptions
)
995 SecCmsMessageRef cmsg
= NULL
;
996 SecCmsContentInfoRef cinfo
;
997 SecCmsSignedDataRef sigd
;
998 SecCertificateRef
*certs
= NULL
;
999 SecKeychainRef dbhandle
;
1003 dbhandle
= certsonlyOptions
->options
->certDBHandle
;
1004 SEC_CHECK0(cnt
= nss_CMSArray_Count((void**)certsonlyOptions
->recipients
),
1005 "please indicate the nickname of a certificate to sign with");
1006 if ((certs
= (SecCertificateRef
*)calloc((cnt
+1), sizeof(SecCertificateRef
))) == NULL
)
1008 sec_error("failed to alloc certs array: %s", strerror(errno
));
1011 for (i
=0; certsonlyOptions
->recipients
&& certsonlyOptions
->recipients
[i
] != NULL
; i
++)
1013 if ((certs
[i
] = CERT_FindCertByNicknameOrEmailAddr(dbhandle
,certsonlyOptions
->recipients
[i
])) == NULL
)
1021 // create the message object on its own pool
1022 SEC_CHECK0(cmsg
= SecCmsMessageCreate(NULL
), "cannot create CMS message");
1023 // build chain of objects: message->signedData->data
1024 SEC_CHECK0(sigd
= SecCmsSignedDataCreateCertsOnly(cmsg
, certs
[0], true),
1025 "cannot create certs only CMS signedData object");
1026 CFRelease(certs
[0]);
1027 for (i
= 1; i
< cnt
; ++i
)
1029 SEC_CHECK2(SecCmsSignedDataAddCertChain(sigd
, certs
[i
]),
1030 "cannot add cert chain for \"%s\"", certsonlyOptions
->recipients
[i
]);
1031 CFRelease(certs
[i
]);
1034 SEC_CHECK0(cinfo
= SecCmsMessageGetContentInfo(cmsg
),
1035 "message has no content info");
1036 SEC_CHECK(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
),
1037 "cannot attach CMS signedData object");
1038 SEC_CHECK0(cinfo
= SecCmsSignedDataGetContentInfo(sigd
),
1039 "signed data has no content info");
1040 SEC_CHECK(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false),
1041 "cannot attach CMS data object");
1050 for (; i
< cnt
; ++i
)
1051 CFRelease(certs
[i
]);
1055 if (cmsg
) SecCmsMessageDestroy(cmsg
);
1060 typedef enum { UNKNOWN
, DECODE
, SIGN
, ENCRYPT
, ENVELOPE
, CERTSONLY
} Mode
;
1062 int cms_util(int argc
, char **argv
)
1065 SecCmsMessageRef cmsg
= NULL
;
1068 Mode mode
= UNKNOWN
;
1069 PK11PasswordFunc pwcb
;
1071 struct decodeOptionsStr decodeOptions
= { 0 };
1072 struct signOptionsStr signOptions
= { 0 };
1073 struct envelopeOptionsStr envelopeOptions
= { 0 };
1074 struct certsonlyOptionsStr certsonlyOptions
= { 0 };
1075 struct encryptOptionsStr encryptOptions
= { 0 };
1076 struct optionsStr options
= { 0 };
1078 static char *ptrarray
[128] = { 0 };
1079 int nrecipients
= 0;
1082 const char *keychainName
= NULL
;
1083 CSSM_DATA input
= { 0,};
1084 CSSM_DATA output
= { 0,};
1085 CSSM_DATA dummy
= { 0, };
1086 CSSM_DATA envmsg
= { 0, };
1093 decodeOptions
.contentFile
= NULL
;
1094 decodeOptions
.suppressContent
= false;
1095 decodeOptions
.headerLevel
= -1;
1096 options
.certUsage
= certUsageEmailSigner
;
1097 options
.password
= NULL
;
1098 signOptions
.nickname
= NULL
;
1099 signOptions
.subjectKeyID
= NULL
;
1100 signOptions
.detached
= false;
1101 signOptions
.signingTime
= false;
1102 signOptions
.smimeProfile
= false;
1103 signOptions
.encryptionKeyPreferenceNick
= NULL
;
1104 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1105 envelopeOptions
.recipients
= NULL
;
1106 encryptOptions
.recipients
= NULL
;
1107 encryptOptions
.envmsg
= NULL
;
1108 encryptOptions
.envFile
= NULL
;
1109 encryptOptions
.bulkalgtag
= SEC_OID_UNKNOWN
;
1110 encryptOptions
.bulkkey
= NULL
;
1111 encryptOptions
.keysize
= -1;
1113 // Parse command line arguments
1114 while ((ch
= getopt(argc
, argv
, "CDEGH:N:OPSTY:Z:c:de:h:i:k:no:p:r:su:vt:")) != -1)
1129 sec_error("option -G only supported with option -S");
1130 result
= 2; /* Trigger usage message. */
1133 signOptions
.signingTime
= true;
1137 sec_error("option -n only supported with option -D");
1138 result
= 2; /* Trigger usage message. */
1141 decodeOptions
.suppressContent
= true;
1142 if (!strcmp(optarg
, "MD2"))
1143 signOptions
.hashAlgTag
= SEC_OID_MD2
;
1144 else if (!strcmp(optarg
, "MD4"))
1145 signOptions
.hashAlgTag
= SEC_OID_MD4
;
1146 else if (!strcmp(optarg
, "MD5"))
1147 signOptions
.hashAlgTag
= SEC_OID_MD5
;
1148 else if (!strcmp(optarg
, "SHA1"))
1149 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1150 else if (!strcmp(optarg
, "SHA256"))
1151 signOptions
.hashAlgTag
= SEC_OID_SHA256
;
1152 else if (!strcmp(optarg
, "SHA384"))
1153 signOptions
.hashAlgTag
= SEC_OID_SHA384
;
1154 else if (!strcmp(optarg
, "SHA512"))
1155 signOptions
.hashAlgTag
= SEC_OID_SHA512
;
1157 sec_error("option -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512");
1163 sec_error("option -N only supported with option -S");
1164 result
= 2; /* Trigger usage message. */
1167 signOptions
.nickname
= strdup(optarg
);
1174 sec_error("option -P only supported with option -S");
1175 result
= 2; /* Trigger usage message. */
1178 signOptions
.smimeProfile
= true;
1185 sec_error("option -T only supported with option -S");
1186 result
= 2; /* Trigger usage message. */
1189 signOptions
.detached
= true;
1193 sec_error("option -Y only supported with option -S");
1194 result
= 2; /* Trigger usage message. */
1197 signOptions
.encryptionKeyPreferenceNick
= strdup(optarg
);
1203 sec_error("option -c only supported with option -D");
1204 result
= 2; /* Trigger usage message. */
1207 if ((decodeOptions
.contentFile
= fopen(optarg
, "rb")) == NULL
)
1209 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1215 #ifdef HAVE_DODUMPSTATES
1219 #endif /* HAVE_DODUMPSTATES */
1222 envFileName
= strdup(optarg
);
1223 encryptOptions
.envFile
= fopen(envFileName
, "rb"); // PR_RDONLY, 00660);
1227 if (mode
!= DECODE
) {
1228 sec_error("option -h only supported with option -D");
1229 result
= 2; /* Trigger usage message. */
1232 decodeOptions
.headerLevel
= atoi(optarg
);
1233 if (decodeOptions
.headerLevel
< 0) {
1234 sec_error("option -h cannot have a negative value");
1239 inFile
= fopen(optarg
,"rb"); // PR_RDONLY, 00660);
1242 sec_error("unable to open \"%s\" for reading: %s", optarg
, strerror(errno
));
1248 keychainName
= optarg
;
1254 sec_error("option -n only supported with option -D");
1255 result
= 2; /* Trigger usage message. */
1258 decodeOptions
.suppressContent
= true;
1261 outFile
= fopen(optarg
, "wb");
1262 if (outFile
== NULL
)
1264 sec_error("unable to open \"%s\" for writing: %s", optarg
, strerror(errno
));
1271 sec_error("option -p must have a value");
1272 result
= 2; /* Trigger usage message. */
1276 options
.password
= (PK11PasswordFunc
)ownpw
;//strdup(optarg);
1282 sec_error("option -r must have a value");
1283 result
= 2; /* Trigger usage message. */
1287 envelopeOptions
.recipients
= ptrarray
;
1288 str
= (char *)optarg
;
1290 tok
= strchr(str
, ',');
1291 if (tok
) *tok
= '\0';
1292 envelopeOptions
.recipients
[nrecipients
++] = strdup(str
);
1293 if (tok
) str
= tok
+ 1;
1295 envelopeOptions
.recipients
[nrecipients
] = NULL
;
1296 encryptOptions
.recipients
= envelopeOptions
.recipients
;
1297 certsonlyOptions
.recipients
= envelopeOptions
.recipients
;
1301 cms_update_single_byte
= 1;
1307 sec_error("option -Z must have a value");
1308 result
= 2; /* Trigger usage message. */
1311 signOptions
.subjectKeyID
= strdup(optarg
);
1317 int usageType
= atoi (strdup(optarg
));
1318 if (usageType
< certUsageSSLClient
|| usageType
> certUsageAnyCA
)
1323 options
.certUsage
= (SECCertUsage
)usageType
;
1331 signOptions
.timestampingURL
= strdup(optarg
);
1332 signOptions
.wantTimestamping
= true;
1335 result
= 2; /* Trigger usage message. */
1343 if (argc
!= 0 || mode
== UNKNOWN
)
1345 result
= 2; /* Trigger usage message. */
1351 if (mode
!= CERTSONLY
)
1352 SECU_FileToItem(&input
, inFile
);
1353 if (inFile
!= stdin
)
1356 fprintf(stderr
, "received commands\n");
1358 /* Call the libsec initialization routines */
1361 check_obsolete_keychain(keychainName
);
1362 options
.certDBHandle
= keychain_open(keychainName
);
1363 if (!options
.certDBHandle
)
1365 sec_perror("SecKeychainOpen", errSecInvalidKeychain
);
1372 fprintf(stderr
, "Got default certdb\n");
1377 decodeOptions
.options
= &options
;
1378 if (encryptOptions
.envFile
)
1380 /* Decoding encrypted-data, so get the bulkkey from an
1381 * enveloped-data message.
1383 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1384 decodeOptions
.options
= &options
;
1385 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
, &decodeOptions
);
1386 if (!encryptOptions
.envmsg
)
1388 sec_error("problem decoding env msg");
1392 rv
= get_enc_params(&encryptOptions
);
1393 decodeOptions
.dkcb
= dkcb
;
1394 decodeOptions
.bulkkey
= encryptOptions
.bulkkey
;
1396 cmsg
= decode(outFile
, &output
, &input
, &decodeOptions
);
1399 sec_error("problem decoding");
1402 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1405 signOptions
.options
= &options
;
1406 cmsg
= signed_data(&signOptions
);
1409 sec_error("problem signing");
1416 sec_error("you must specify an envelope file with -e");
1420 encryptOptions
.options
= &options
;
1421 encryptOptions
.input
= &input
;
1422 encryptOptions
.outfile
= outFile
;
1423 if (!encryptOptions
.envFile
) {
1424 encryptOptions
.envFile
= fopen(envFileName
,"wb"); //PR_WRONLY|PR_CREATE_FILE, 00660);
1425 if (!encryptOptions
.envFile
)
1427 sec_error("failed to create file %s: %s", envFileName
, strerror(errno
));
1434 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1435 decodeOptions
.options
= &options
;
1436 encryptOptions
.envmsg
= decode(NULL
, &dummy
, &envmsg
,
1438 if (encryptOptions
.envmsg
== NULL
)
1440 sec_error("problem decrypting env msg");
1446 /* decode an enveloped-data message to get the bulkkey (create
1447 * a new one if neccessary)
1449 rv
= get_enc_params(&encryptOptions
);
1450 /* create the encrypted-data message */
1451 cmsg
= encrypted_data(&encryptOptions
);
1454 sec_error("problem encrypting");
1458 if (encryptOptions
.bulkkey
)
1460 CFRelease(encryptOptions
.bulkkey
);
1461 encryptOptions
.bulkkey
= NULL
;
1465 envelopeOptions
.options
= &options
;
1466 cmsg
= enveloped_data(&envelopeOptions
);
1469 sec_error("problem enveloping");
1474 certsonlyOptions
.options
= &options
;
1475 cmsg
= signed_data_certsonly(&certsonlyOptions
);
1478 sec_error("problem with certs-only");
1483 /* Already handled above. */
1487 if ( (mode
== SIGN
|| mode
== ENVELOPE
|| mode
== CERTSONLY
)
1490 SecArenaPoolRef arena
= NULL
;
1491 SecCmsEncoderRef ecx
;
1492 CSSM_DATA output
= {};
1494 SEC_CHECK(SecArenaPoolCreate(1024, &arena
), "failed to create arenapool");
1495 pwcb
= (PK11PasswordFunc
)((options
.password
!= NULL
) ? ownpw
: NULL
);
1496 pwcb_arg
= (options
.password
!= NULL
) ? (void *)options
.password
: NULL
;
1498 fprintf(stderr
, "cmsg [%p]\n", cmsg
);
1499 fprintf(stderr
, "arena [%p]\n", arena
);
1501 fprintf(stderr
, "password [%s]\n", (char *)pwcb_arg
);
1503 fprintf(stderr
, "password [NULL]\n");
1506 SEC_CHECK(SecCmsEncoderCreate(cmsg
,
1507 NULL
, NULL
, /* DER output callback */
1508 &output
, arena
, /* destination storage */
1509 pwcb
, pwcb_arg
, /* password callback */
1510 NULL
, NULL
, /* decrypt key callback */
1511 NULL
, NULL
, /* detached digests */
1513 "cannot create encoder context");
1516 fprintf(stderr
, "input len [%ld]\n", input
.Length
);
1519 for (j
= 0; j
< input
.Length
; ++j
)
1520 fprintf(stderr
, "%2x%c", input
.Data
[j
], (j
>0&&j%35
==0)?'\n':' ');
1524 if (input
.Length
> 0) { /* skip if certs-only (or other zero content) */
1525 SEC_CHECK(SecCmsEncoderUpdate(ecx
, (char *)input
.Data
, input
.Length
),
1526 "failed to add data to encoder");
1529 SEC_CHECK(SecCmsEncoderFinish(ecx
), "failed to encode data");
1532 fprintf(stderr
, "encoding passed\n");
1535 /*PR_Write(output.data, output.len);*/
1536 fwrite(output
.Data
, output
.Length
, 1, outFile
);
1538 fprintf(stderr
, "wrote to file\n");
1540 SecArenaPoolFree(arena
, false);
1545 SecCmsMessageDestroy(cmsg
);
1546 if (outFile
!= stdout
)
1549 if (decodeOptions
.contentFile
)
1550 fclose(decodeOptions
.contentFile
);
1556 #pragma mark ================ Misc from NSS ===================
1557 // from /security/nss/cmd/lib/secutil.c
1560 SECU_FileToItem(CSSM_DATA
*dst
, FILE *src
)
1562 const int kReadSize
= 4096;
1563 size_t bytesRead
, totalRead
= 0;
1567 /* Make room in dst for the new data. */
1568 dst
->Length
+= kReadSize
;
1569 dst
->Data
= realloc(dst
->Data
, dst
->Length
);
1571 return 1 /* @@@ memFullErr */;
1573 bytesRead
= fread (&dst
->Data
[totalRead
], 1, kReadSize
, src
);
1574 totalRead
+= bytesRead
;
1575 } while (bytesRead
== kReadSize
);
1579 /* We are here, but there's no EOF. This is bad */
1585 return 1 /* @@@ ioErr */;
1588 /* Trim down the buffer. */
1589 dst
->Length
= totalRead
;
1590 dst
->Data
= realloc(dst
->Data
, totalRead
);
1592 return 1 /* @@@ memFullErr */;