2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
7 * Changes Copyright (c) 2004
8 * Gunnar Ritter. All rights reserved.
11 * Parts of this file are derived from the Mozilla NSS 3.9.2 source,
12 * mozilla/security/nss/cmd/smimetools/cmsutil.c. Therefore:
14 * The contents of this file are subject to the Mozilla Public License
15 * Version 1.1 (the "License"); you may not use this file except in
16 * compliance with the License. You may obtain a copy of the License
17 * at http://www.mozilla.org/MPL/
19 * Software distributed under the License is distributed on an "AS
20 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
21 * implied. See the License for the specific language governing
22 * rights and limitations under the License.
24 * The Original Code is the Netscape security libraries.
26 * The Initial Developer of the Original Code is Netscape
27 * Communications Corporation. Portions created by Netscape are
28 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
36 static char sccsid
[] = "@(#)nss.c 1.48 (gritter) 8/4/07";
52 static struct termios otio
;
53 static sigjmp_buf nssjmp
;
73 #include <private/pprio.h>
77 #ifndef HAVE_CERTAltNameEncodedContext
79 * NSS 3.11.5 neither installs genname.h nor provides this
80 * structure otherwise, so define it here.
82 typedef struct CERTAltNameEncodedContextStr
{
83 SECItem
**encodedGenName
;
84 } CERTAltNameEncodedContext
;
85 #endif /* !HAVE_CERTAltNameEncodedContext */
89 static char *password_cb(PK11SlotInfo
*slot
, PRBool retry
, void *arg
);
90 static SECStatus
bad_cert_cb(void *arg
, PRFileDesc
*fd
);
91 static enum okay
nss_check_host(const char *server
, struct sock
*sp
);
92 static const char *bad_cert_str(void);
93 static enum okay
nss_init(void);
94 static void nss_select_method(const char *uhp
);
95 static CERTCertificate
*get_signer_cert(char *addr
);
96 static FILE *encode(FILE *ip
, FILE **hp
, FILE **bp
, NSSCMSMessage
*msg
,
97 void (*cb
)(void *, const char *, unsigned long));
98 static void decoder_cb(void *arg
, const char *buf
, unsigned long len
);
99 static void base64_cb(void *arg
, const char *buf
, unsigned long len
);
100 static int verify1(struct message
*m
, int n
);
101 static struct message
*getsig(struct message
*m
, int n
, NSSCMSMessage
**msg
);
102 static enum okay
getdig(struct message
*m
, int n
, SECItem
***digests
,
103 PLArenaPool
**poolp
, SECAlgorithmID
**algids
);
104 static void nsscatch(int s
);
105 static void dumpcert(CERTCertificate
*cert
, FILE *op
);
106 static enum okay
getcipher(const char *to
, SECOidTag
*alg
, int *key
);
109 password_cb(PK11SlotInfo
*slot
, PRBool retry
, void *arg
)
111 sighandler_type saveint
;
116 saveint
= safe_signal(SIGINT
, SIG_IGN
);
117 if (sigsetjmp(nssjmp
, 1) == 0) {
118 if (saveint
!= SIG_IGN
)
119 safe_signal(SIGINT
, nsscatch
);
120 pass
= getpassword(&otio
, &reset_tio
, arg
);
122 safe_signal(SIGINT
, saveint
);
125 return PL_strdup(pass
);
129 bad_cert_cb(void *arg
, PRFileDesc
*fd
)
131 if (PORT_GetError() == SSL_ERROR_BAD_CERT_DOMAIN
)
133 * We must not use this result. NSS verifies host names
134 * according to RFC 2818, but we must verify host names
135 * according to RFC 2595. The rules are different:
137 * - RFC 2818 says that if both a dNSName and a CN are
138 * contained in the peer certificate, only the dNSName
139 * is used. RFC 2595 encourages to use both.
141 * - RFC 2818 allows the wildcard '*' in any component
142 * of the host name. RFC 2595 allows it only as the
143 * "left-most name component".
145 * So ignore it and verify separately.
148 fprintf(stderr
, "Error in certificate: %s.\n", bad_cert_str());
149 return ssl_vrfy_decide() == OKAY
? SECSuccess
: SECFailure
;
153 * Host name checking according to RFC 2595.
156 nss_check_host(const char *server
, struct sock
*sp
)
158 CERTCertificate
*cert
;
164 CERTAltNameEncodedContext ec
;
166 const SEC_ASN1Template gntempl
[] = {
167 { SEC_ASN1_SEQUENCE_OF
, 0, SEC_AnyTemplate
}
170 if ((cert
= SSL_PeerCertificate(sp
->s_prfd
)) == NULL
) {
171 fprintf(stderr
, "no certificate from \"%s\"\n", server
);
174 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
175 if (CERT_FindCertExtension(cert
, SEC_OID_X509_SUBJECT_ALT_NAME
,
176 &altname
) == SECSuccess
&&
177 SEC_ASN1DecodeItem(arena
, &ec
, gntempl
,
178 &altname
) == SECSuccess
&&
179 ec
.encodedGenName
!= NULL
) {
180 for (i
= 0; ec
.encodedGenName
[i
] != NULL
; i
++) {
181 gn
= CERT_DecodeGeneralName(arena
, ec
.encodedGenName
[i
],
183 if (gn
->type
== certDNSName
) {
184 char *dn
= ac_alloc(gn
->name
.other
.len
+ 1);
185 memcpy(dn
, gn
->name
.other
.data
,
187 dn
[gn
->name
.other
.len
] = '\0';
190 "Comparing DNS name: \"%s\"\n",
192 if (rfc2595_hostname_match(server
, dn
)
201 if ((cn
= CERT_GetCommonName(&cert
->subject
)) != NULL
) {
203 fprintf(stderr
, "Comparing common name: \"%s\"\n", cn
);
204 ok
= rfc2595_hostname_match(server
, cn
);
207 fprintf(stderr
, "host certificate does not match \"%s\"\n",
211 PORT_FreeArena(arena
, PR_FALSE
);
212 CERT_DestroyCertificate(cert
);
221 ec
= PORT_GetError();
222 return nss_strerror(ec
);
228 static int initialized
;
231 verbose
= value("verbose") != NULL
;
232 if (initialized
== 0) {
233 if ((cp
= value("nss-config-dir")) == NULL
) {
234 fputs("Missing \"nss-config-dir\" variable.\n", stderr
);
239 PK11_SetPasswordFunc(password_cb
);
240 if (NSS_Init(cp
) == SECSuccess
) {
241 NSS_SetDomesticPolicy();
245 nss_gen_err("Error initializing NSS");
252 nss_select_method(const char *uhp
)
261 methods
= SSL2
|SSL3
|TLS1
;
262 cp
= ssl_method_string(uhp
);
264 if (equal(cp
, "ssl2"))
266 else if (equal(cp
, "ssl3"))
268 else if (equal(cp
, "tls1"))
271 fprintf(stderr
, catgets(catd
, CATSET
, 244,
272 "Invalid SSL method \"%s\"\n"), cp
);
275 if (value("ssl-v2-allow") == NULL
)
277 SSL_OptionSetDefault(SSL_ENABLE_SSL2
, methods
&SSL2
? PR_TRUE
:PR_FALSE
);
278 SSL_OptionSetDefault(SSL_ENABLE_SSL3
, methods
&SSL3
? PR_TRUE
:PR_FALSE
);
279 SSL_OptionSetDefault(SSL_ENABLE_TLS
, methods
&TLS1
? PR_TRUE
:PR_FALSE
);
283 ssl_open(const char *server
, struct sock
*sp
, const char *uhp
)
285 PRFileDesc
*fdp
, *fdc
;
287 if (nss_init() == STOP
)
289 ssl_set_vrfy_level(uhp
);
290 nss_select_method(uhp
);
291 if ((fdp
= PR_ImportTCPSocket(sp
->s_fd
)) == NULL
) {
292 nss_gen_err("Error importing OS file descriptor");
295 if ((fdc
= SSL_ImportFD(NULL
, fdp
)) == NULL
) {
296 nss_gen_err("Error importing NSPR file descriptor");
300 SSL_SetURL(fdc
, server
);
301 SSL_SetPKCS11PinArg(fdc
, NULL
);
302 SSL_BadCertHook(fdc
, bad_cert_cb
, NULL
);
303 if (SSL_ResetHandshake(fdc
, PR_FALSE
) != SECSuccess
) {
304 nss_gen_err("Cannot reset NSS handshake");
308 if (SSL_ForceHandshake(fdc
) != 0) {
309 nss_gen_err("SSL/TLS handshake failed");
314 if (nss_check_host(server
, sp
) != OKAY
&& ssl_vrfy_decide() != OKAY
) {
321 char *cipher
, *issuer
, *subject
;
322 int keysize
, secretkeysize
;
324 if (SSL_SecurityStatus(fdc
, NULL
, &cipher
,
325 &keysize
, &secretkeysize
,
326 &issuer
, &subject
) == SECSuccess
) {
327 fprintf(stderr
, "SSL parameters: cipher=%s, "
328 "keysize=%d, secretkeysize=%d,\n"
331 cipher
, keysize
, secretkeysize
,
337 nss_gen_err("Could not read status information");
343 nss_gen_err(const char *fmt
, ...)
350 vfprintf(stderr
, fmt
, ap
);
352 if ((len
= PR_GetErrorTextLength()) > 0) {
353 text
= ac_alloc(len
);
354 if (PR_GetErrorText(text
) > 0)
355 fprintf(stderr
, ": %s\n", text
);
358 fprintf(stderr
, ": %s.\n", nss_strerror(PR_GetError()));
362 smime_sign(FILE *ip
, struct header
*headp
)
365 NSSCMSContentInfo
*content
;
366 NSSCMSSignedData
*data
;
367 NSSCMSSignerInfo
*info
;
368 CERTCertificate
*cert
;
369 CERTCertDBHandle
*handle
;
373 if (nss_init() != OKAY
)
375 if ((addr
= myorigin(headp
)) == NULL
) {
376 fprintf(stderr
, "No \"from\" address for signing specified\n");
379 if ((cert
= get_signer_cert(addr
)) == NULL
)
381 handle
= CERT_GetDefaultCertDB();
382 if ((msg
= NSS_CMSMessage_Create(NULL
)) == NULL
) {
383 fprintf(stderr
, "Cannot create CMS message.\n");
386 if ((data
= NSS_CMSSignedData_Create(msg
)) == NULL
) {
387 fprintf(stderr
, "Cannot create CMS signed data.\n");
390 content
= NSS_CMSMessage_GetContentInfo(msg
);
391 if (NSS_CMSContentInfo_SetContent_SignedData(msg
, content
, data
)
393 fprintf(stderr
, "Cannot attach CMS signed data.\n");
396 content
= NSS_CMSSignedData_GetContentInfo(data
);
397 if (NSS_CMSContentInfo_SetContent_Data(msg
, content
, NULL
, PR_TRUE
)
399 fprintf(stderr
, "Cannot attach CMS data.\n");
402 if ((info
= NSS_CMSSignerInfo_Create(msg
, cert
, SEC_OID_SHA1
)) == 0) {
403 fprintf(stderr
, "Cannot create signed information.\n");
406 if (NSS_CMSSignerInfo_IncludeCerts(info
, NSSCMSCM_CertOnly
,
407 certUsageEmailSigner
) != SECSuccess
) {
408 fprintf(stderr
, "Cannot include certificate.\n");
411 if (NSS_CMSSignerInfo_AddSigningTime(info
, PR_Now()) != SECSuccess
) {
412 fprintf(stderr
, "Cannot add signing time.\n");
415 if (NSS_CMSSignerInfo_AddSMIMECaps(info
) != SECSuccess
) {
416 fprintf(stderr
, "Cannot add S/MIME capabilities.\n");
419 NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(info
, cert
, handle
);
420 NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(info
, cert
, handle
);
421 if (NSS_CMSSignedData_AddCertificate(data
, cert
) != SECSuccess
) {
422 fprintf(stderr
, "Cannot add encryption certificate.\n");
425 if (NSS_CMSSignedData_AddSignerInfo(data
, info
) != SECSuccess
) {
426 fprintf(stderr
, "Cannot add signer information.\n");
429 CERT_DestroyCertificate(cert
);
430 if ((sp
= encode(ip
, &hp
, &bp
, msg
, base64_cb
)) == NULL
) {
431 NSS_CMSMessage_Destroy(msg
);
434 NSS_CMSMessage_Destroy(msg
);
435 return smime_sign_assemble(hp
, bp
, sp
);
441 int *msgvec
= vp
, *ip
;
444 if (nss_init() != OKAY
)
446 ssl_vrfy_level
= VRFY_STRICT
;
447 for (ip
= msgvec
; *ip
; ip
++) {
448 setdot(&message
[*ip
-1]);
449 ec
|= verify1(&message
[*ip
-1], *ip
);
455 smime_encrypt(FILE *ip
, const char *ignored
, const char *to
)
458 NSSCMSContentInfo
*content
;
459 NSSCMSEnvelopedData
*data
;
460 NSSCMSRecipientInfo
*info
;
461 CERTCertificate
*cert
[2];
462 CERTCertDBHandle
*handle
;
469 if (nss_init() != OKAY
)
471 handle
= CERT_GetDefaultCertDB();
472 vn
= ac_alloc(vs
= strlen(to
) + 30);
473 snprintf(vn
, vs
, "smime-nickname-%s", to
);
474 nickname
= value(vn
);
476 if ((cert
[0] = CERT_FindCertByNicknameOrEmailAddr(handle
,
477 nickname
? nickname
: (char *)to
)) == NULL
) {
479 fprintf(stderr
, "Cannot find certificate \"%s\".\n",
482 fprintf(stderr
, "Cannot find certificate for <%s>.\n",
487 if (getcipher(to
, &tag
, &keysize
) != OKAY
)
489 if ((msg
= NSS_CMSMessage_Create(NULL
)) == NULL
) {
490 fprintf(stderr
, "Cannot create CMS message.\n");
493 if ((data
= NSS_CMSEnvelopedData_Create(msg
, tag
, keysize
)) == NULL
) {
494 fprintf(stderr
, "Cannot create enveloped data.\n");
497 content
= NSS_CMSMessage_GetContentInfo(msg
);
498 if (NSS_CMSContentInfo_SetContent_EnvelopedData(msg
, content
, data
)
500 fprintf(stderr
, "Cannot attach enveloped data.\n");
503 content
= NSS_CMSEnvelopedData_GetContentInfo(data
);
504 if (NSS_CMSContentInfo_SetContent_Data(msg
, content
, NULL
, PR_FALSE
)
506 fprintf(stderr
, "Cannot attach CMS data.\n");
509 if ((info
= NSS_CMSRecipientInfo_Create(msg
, cert
[0])) == NULL
) {
510 fprintf(stderr
, "Cannot create CMS recipient information.\n");
513 if (NSS_CMSEnvelopedData_AddRecipient(data
, info
) != SECSuccess
) {
514 fprintf(stderr
, "Cannot add CMS recipient information.\n");
517 CERT_DestroyCertificate(cert
[0]);
518 if ((yp
= encode(ip
, &hp
, &pp
, msg
, base64_cb
)) == NULL
)
520 NSS_CMSMessage_Destroy(msg
);
521 return smime_encrypt_assemble(hp
, yp
);
525 smime_decrypt(struct message
*m
, const char *to
, const char *cc
, int signcall
)
527 NSSCMSDecoderContext
*ctx
;
531 size_t bufsize
= 0, buflen
, count
;
539 if ((yp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
)
541 if (nss_init() != OKAY
)
543 if ((op
= Ftemp(&cp
, "Rp", "w+", 0600, 1)) == NULL
) {
549 if ((ctx
= NSS_CMSDecoder_Start(NULL
,
551 password_cb
, "Pass phrase:",
552 NULL
, NULL
)) == NULL
) {
553 fprintf(stderr
, "Cannot start decoder.\n");
557 if ((smime_split(yp
, &hp
, &bp
, size
, 1)) == STOP
)
560 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, bp
, 0) != NULL
) {
563 if ((cp
= thisfield(buf
, "content-transfer-encoding")) != NULL
)
564 if (ascncasecmp(cp
, "binary", 7) == 0)
567 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, bp
, 0) != NULL
) {
569 NSS_CMSDecoder_Update(ctx
, buf
, buflen
);
573 mime_fromb64_b(&in
, &out
, 0, bp
);
574 NSS_CMSDecoder_Update(ctx
, out
.s
, out
.l
);
579 if ((msg
= NSS_CMSDecoder_Finish(ctx
)) == NULL
) {
580 fprintf(stderr
, "Failed to decode message.\n");
585 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
586 for (i
= 0; i
< nlevels
; i
++) {
587 NSSCMSContentInfo
*content
;
590 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
591 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
592 if (tag
== SEC_OID_PKCS7_DATA
) {
593 const char *fld
= "X-Encryption-Cipher";
597 alg
= NSS_CMSContentInfo_GetContentEncAlgTag(content
);
598 keysize
= NSS_CMSContentInfo_GetBulkKeySize(content
);
599 fseek(hp
, 0L, SEEK_END
);
603 NSS_CMSMessage_Destroy(msg
);
606 setinput(&mb
, m
, NEED_BODY
);
607 return (struct message
*)-1;
609 fprintf(hp
, "%s: none\n", fld
);
611 case SEC_OID_RC2_CBC
:
612 fprintf(hp
, "%s: RC2, %d bits\n", fld
, keysize
);
614 case SEC_OID_DES_CBC
:
615 fprintf(hp
, "%s: DES, 56 bits\n", fld
);
617 case SEC_OID_DES_EDE3_CBC
:
618 fprintf(hp
, "%s: 3DES, 112/168 bits\n", fld
);
620 case SEC_OID_FORTEZZA_SKIPJACK
:
621 fprintf(hp
, "%s: Fortezza\n", fld
);
624 fprintf(hp
, "%s: unknown type %lu\n", fld
,
631 NSS_CMSMessage_Destroy(msg
);
635 return smime_decrypt_assemble(m
, hp
, op
);
638 static CERTCertificate
*
639 get_signer_cert(char *addr
)
641 CERTCertDBHandle
*handle
;
643 CERTCertListNode
*node
;
644 CERTCertificate
*cert
= NULL
;
651 vn
= ac_alloc(vs
= strlen(addr
) + 30);
652 snprintf(vn
, vs
, "smime-sign-nickname-%s", addr
);
653 if ((nick
= value(vn
)) == NULL
)
654 nick
= value("smime-sign-nickname");
656 handle
= CERT_GetDefaultCertDB();
658 cert
= CERT_FindCertByNickname(handle
, nick
);
660 fprintf(stderr
, "No certificate \"%s\" found.\n", nick
);
663 if ((list
= CERT_FindUserCertsByUsage(handle
, certUsageEmailSigner
,
664 PR_TRUE
, PR_TRUE
, NULL
)) == NULL
) {
665 fprintf(stderr
, "Cannot find any certificates for signing.\n");
668 for (node
= CERT_LIST_HEAD(list
); !CERT_LIST_END(node
, list
);
669 node
= CERT_LIST_NEXT(node
)) {
670 if ((cp
= CERT_GetCertEmailAddress(&node
->cert
->subject
))
671 != NULL
&& asccasecmp(cp
, addr
) == 0) {
677 for (node
= CERT_LIST_HEAD(list
);
678 !CERT_LIST_END(node
, list
) && cert
== NULL
;
679 node
= CERT_LIST_NEXT(node
)) {
680 cp
= CERT_GetFirstEmailAddress(node
->cert
);
682 if (asccasecmp(cp
, addr
) == 0) {
686 cp
= CERT_GetNextEmailAddress(node
->cert
, cp
);
692 "More than one signing certificate found for <%s>.\n"
693 "Use the smime-sign-nickname variable.\n", addr
);
698 "Cannot find a signing certificate for <%s>.\n",
704 encode(FILE *ip
, FILE **hp
, FILE **bp
, NSSCMSMessage
*msg
,
705 void (*cb
)(void *, const char *, unsigned long))
707 NSSCMSEncoderContext
*ctx
;
708 char *buf
= NULL
, *cp
;
709 size_t bufsize
= 0, buflen
, count
;
712 if (smime_split(ip
, hp
, bp
, -1, 0) == STOP
)
714 if ((op
= Ftemp(&cp
, "Ry", "w+", 0600, 1)) == NULL
) {
720 if ((ctx
= NSS_CMSEncoder_Start(msg
,
723 password_cb
, "Pass phrase:",
725 NULL
, NULL
)) == NULL
) {
726 fprintf(stderr
, "Cannot create encoder context.\n");
731 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, *bp
, 0) != NULL
) {
732 buf
[buflen
-1] = '\r';
734 if (NSS_CMSEncoder_Update(ctx
, buf
, buflen
+1) != 0) {
735 fprintf(stderr
, "Failed to add data to encoder.\n");
741 if (NSS_CMSEncoder_Finish(ctx
) != 0) {
742 fprintf(stderr
, "Failed to encode data.\n");
747 cb(op
, (void *)-1, 0);
759 decoder_cb(void *arg
, const char *buf
, unsigned long len
)
762 fwrite(buf
, 1, len
, arg
);
766 base64_cb(void *arg
, const char *buf
, unsigned long len
)
768 static char back
[972];
772 if (arg
&& buf
&& buf
!= (void *)-1) {
774 while (len
- pos
>= sizeof back
- fill
) {
775 memcpy(&back
[fill
], &buf
[pos
], sizeof back
- fill
);
776 mime_write(back
, sizeof back
, arg
,
777 CONV_TOB64
, TD_NONE
, NULL
, 0,
779 pos
+= sizeof back
- fill
;
782 memcpy(&back
[fill
], &buf
[pos
], len
- pos
);
784 } else if (buf
== (void *)-1) {
785 mime_write(back
, fill
, arg
,
786 CONV_TOB64
, TD_NONE
, NULL
, 0,
793 verify1(struct message
*m
, int n
)
798 SECAlgorithmID
**algids
;
799 CERTCertDBHandle
*handle
;
805 if ((m
= getsig(m
, n
, &msg
)) == NULL
)
807 sender
= getsender(m
);
808 handle
= CERT_GetDefaultCertDB();
809 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
810 for (i
= 0; i
< nlevels
; i
++) {
811 NSSCMSContentInfo
*content
;
814 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
815 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
816 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
817 NSSCMSSignedData
*data
;
820 if ((data
= NSS_CMSContentInfo_GetContent(content
))
822 fprintf(stderr
, "Signed data missing for "
827 if (!NSS_CMSSignedData_HasDigests(data
)) {
828 algids
= NSS_CMSSignedData_GetDigestAlgs(data
);
829 if (getdig(m
, n
, &digests
, &poolp
, algids
)
834 if (NSS_CMSSignedData_SetDigests(data
, algids
,
837 fprintf(stderr
, "Cannot set digests "
838 "for message %d.\n", n
);
842 PORT_FreeArena(poolp
, PR_FALSE
);
844 if (NSS_CMSSignedData_ImportCerts(data
, handle
,
845 certUsageEmailSigner
,
846 PR_FALSE
) != SECSuccess
) {
847 fprintf(stderr
, "Cannot temporarily import "
853 nsigners
= NSS_CMSSignedData_SignerInfoCount(data
);
855 fprintf(stderr
, "Message %d has no signers.\n",
860 if (!NSS_CMSSignedData_HasDigests(data
)) {
861 fprintf(stderr
, "Message %d has no digests.\n",
866 for (j
= 0; j
< nsigners
; j
++) {
868 NSSCMSSignerInfo
*info
;
869 NSSCMSVerificationStatus vs
;
871 CERTCertificate
*cert
;
875 info
= NSS_CMSSignedData_GetSignerInfo(data
, j
);
876 cert
= NSS_CMSSignerInfo_GetSigningCertificate
878 bad
= NSS_CMSSignedData_VerifySignerInfo(data
,
880 certUsageEmailSigner
);
881 vs
= NSS_CMSSignerInfo_GetVerificationStatus
883 svs
= NSS_CMSUtil_VerificationStatusToString
885 addr
= CERT_GetCertEmailAddress(&cert
->subject
);
886 if (sender
!= NULL
&& addr
!= NULL
&&
887 asccasecmp(sender
, addr
) == 0)
890 addr
= CERT_GetFirstEmailAddress(cert
);
891 while (sender
&& addr
) {
892 if (!asccasecmp(sender
, addr
)) {
896 addr
= CERT_GetNextEmailAddress
900 if (CERT_VerifyCertNow(handle
,
902 certUsageEmailSigner
,
904 fprintf(stderr
, "Bad certificate for "
907 addr
? addr
: "?", n
,
912 fprintf(stderr
, "Bad status for "
921 else if (status
== 0)
926 if (foundsender
== 0) {
928 fprintf(stderr
, "Signers of message "
929 "%d do not include the sender <%s>\n",
933 fprintf(stderr
, "Warning: Message %d has no From: "
934 "header field.\n", n
);
935 } else if (status
== 1)
936 printf("Message %d was verified successfully.\n", n
);
938 fprintf(stderr
, "No verification information found in "
940 NSS_CMSMessage_Destroy(msg
);
944 static struct message
*
945 getsig(struct message
*m
, int n
, NSSCMSMessage
**msg
)
948 char *ct
, *pt
, *boundary
= NULL
, *cte
;
950 size_t bufsize
= 0, buflen
, count
, boundlen
= -1;
953 NSSCMSDecoderContext
*decctx
;
959 loop
: if ((ct
= hfield("content-type", m
)) == NULL
)
961 if (strncmp(ct
, "application/x-pkcs7-mime", 24) == 0 ||
962 strncmp(ct
, "application/pkcs7-mime", 22) == 0) {
963 to
= hfield("to", m
);
964 cc
= hfield("cc", m
);
965 if ((x
= smime_decrypt(m
, to
, cc
, 1)) == NULL
)
967 if (x
!= (struct message
*)-1) {
972 } else if (strncmp(ct
, "multipart/signed", 16) ||
973 (pt
= mime_getparam("protocol", ct
)) == NULL
||
974 strcmp(pt
, "application/x-pkcs7-signature") &&
975 strcmp(pt
, "application/pkcs7-signature") ||
976 (boundary
= mime_getboundary(ct
)) == NULL
) {
978 "Message %d is not an S/MIME signed message.\n", n
);
981 boundlen
= strlen(boundary
);
982 if ((decctx
= NSS_CMSDecoder_Start(NULL
, NULL
, NULL
,
983 password_cb
, "Pass phrase:",
984 NULL
, NULL
)) == NULL
) {
985 fprintf(stderr
, "Cannot start decoder.\n");
988 if ((fp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
) {
995 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, fp
, 0) != NULL
) {
996 if (detached
&& boundary
&& buflen
>= boundlen
+ 1 &&
997 strncmp(buf
, boundary
, boundlen
) == 0) {
998 if (buf
[boundlen
] == '\n') {
1003 fprintf(stderr
, "Message %d has too "
1004 "many parts.\n", n
);
1010 if (buf
[boundlen
] == '-' && buf
[boundlen
+1] == '-' &&
1011 buf
[boundlen
+2] == '\n')
1013 } else if (buf
[0] == '\n') {
1017 if ((!detached
|| part
== 2) && inhdr
== 0) {
1019 NSS_CMSDecoder_Update(decctx
, buf
, buflen
);
1023 mime_fromb64_b(&in
, &out
, 0, fp
);
1024 NSS_CMSDecoder_Update(decctx
, out
.s
, out
.l
);
1028 if (buflen
== 1 && buf
[0] == '\n')
1030 if (inhdr
&& (cte
= thisfield(buf
, "content-transfer-encoding"))
1031 != NULL
&& ascncasecmp(cte
, "binary", 7) == 0)
1035 if ((*msg
= NSS_CMSDecoder_Finish(decctx
)) == NULL
) {
1036 fprintf(stderr
, "Failed to decode signature for message %d.\n",
1044 getdig(struct message
*m
, int n
, SECItem
***digests
,
1045 PLArenaPool
**poolp
, SECAlgorithmID
**algids
)
1047 char *ct
, *pt
, *boundary
;
1049 size_t bufsize
= 0, buflen
, count
, boundlen
;
1053 NSSCMSDigestContext
*digctx
;
1055 *poolp
= PORT_NewArena(1024);
1056 if ((ct
= hfield("content-type", m
)) == NULL
||
1057 strncmp(ct
, "multipart/signed", 16) ||
1058 (pt
= mime_getparam("protocol", ct
)) == NULL
||
1059 strcmp(pt
, "application/x-pkcs7-signature") &&
1060 strcmp(pt
, "application/pkcs7-signature") ||
1061 (boundary
= mime_getboundary(ct
)) == NULL
) {
1063 "Message %d is not an S/MIME signed message.\n", n
);
1066 boundlen
= strlen(boundary
);
1067 if ((digctx
= NSS_CMSDigestContext_StartMultiple(algids
)) == NULL
) {
1068 fprintf(stderr
, "Cannot start digest computation.\n");
1071 if ((fp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
) {
1077 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, fp
, 0) != NULL
) {
1078 if (buflen
>= boundlen
+ 1 &&
1079 strncmp(buf
, boundary
, boundlen
) == 0) {
1080 if (buf
[boundlen
] == '\n') {
1085 if (buf
[boundlen
] == '-' && buf
[boundlen
+1] == '-' &&
1086 buf
[boundlen
+2] == '\n')
1091 NSS_CMSDigestContext_Update(digctx
,
1092 (unsigned char *)"\r\n", 2);
1095 if (buf
[buflen
-1] == '\n') {
1099 NSS_CMSDigestContext_Update(digctx
,
1100 (unsigned char *)buf
, buflen
);
1105 if (NSS_CMSDigestContext_FinishMultiple(digctx
,
1106 *poolp
, digests
) != SECSuccess
) {
1107 fprintf(stderr
, "Error creating digest for message %d\n", n
);
1117 tcsetattr(0, TCSADRAIN
, &otio
);
1118 siglongjmp(nssjmp
, s
);
1122 smime_certsave(struct message
*m
, int n
, FILE *op
)
1125 CERTCertDBHandle
*handle
;
1126 int nlevels
, i
, cnt
= 0;
1127 enum okay ok
= OKAY
;
1129 if (nss_init() == STOP
)
1131 if ((m
= getsig(m
, n
, &msg
)) == NULL
)
1133 handle
= CERT_GetDefaultCertDB();
1134 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
1135 for (i
= 0; i
< nlevels
; i
++) {
1136 NSSCMSContentInfo
*content
;
1139 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
1140 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
1141 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
1142 NSSCMSSignedData
*data
;
1145 if ((data
= NSS_CMSContentInfo_GetContent(content
))
1147 fprintf(stderr
, "Signed data missing for "
1148 "message %d.\n", n
);
1152 if (NSS_CMSSignedData_ImportCerts(data
, handle
,
1153 certUsageEmailSigner
,
1154 PR_FALSE
) != SECSuccess
) {
1155 fprintf(stderr
, "Cannot temporarily import "
1157 "message %d.\n", n
);
1161 nsigners
= NSS_CMSSignedData_SignerInfoCount(data
);
1162 if (nsigners
== 0) {
1163 fprintf(stderr
, "Message %d has no signers.\n",
1168 for (j
= 0; j
< nsigners
; j
++) {
1169 NSSCMSSignerInfo
*info
;
1170 CERTCertificateList
*list
;
1171 CERTCertificate
*cert
;
1174 info
= NSS_CMSSignedData_GetSignerInfo(data
, j
);
1175 list
= NSS_CMSSignerInfo_GetCertList(info
);
1177 for (k
= 0; k
< list
->len
; k
++) {
1178 cert
= (CERTCertificate
*)
1184 cert
= NSS_CMSSignerInfo_GetSigningCertificate
1193 NSS_CMSMessage_Destroy(msg
);
1195 fprintf(stderr
, "No certificates found in message %d.\n", n
);
1202 dumpcert(CERTCertificate
*cert
, FILE *op
)
1204 fprintf(op
, "subject=%s\n", cert
->subjectName
);
1205 fprintf(op
, "issuer=%s\n", cert
->issuerName
);
1206 fputs("-----BEGIN CERTIFICATE-----\n", op
);
1207 mime_write(cert
->derCert
.data
,
1208 cert
->derCert
.len
, op
,
1209 CONV_TOB64
, TD_NONE
, NULL
, 0,
1211 fputs("-----END CERTIFICATE-----\n", op
);
1215 getcipher(const char *to
, SECOidTag
*alg
, int *key
)
1221 *alg
= SEC_OID_DES_EDE3_CBC
;
1222 vn
= ac_alloc(vs
= strlen(to
) + 30);
1223 snprintf(vn
, vs
, "smime-cipher-%s", to
);
1224 if ((cp
= value(vn
)) != NULL
) {
1225 if (strcmp(cp
, "rc2-40") == 0) {
1226 *alg
= SEC_OID_RC2_CBC
;
1228 } else if (strcmp(cp
, "rc2-64") == 0) {
1229 *alg
= SEC_OID_RC2_CBC
;
1231 } else if (strcmp(cp
, "rc2-128") == 0) {
1232 *alg
= SEC_OID_RC2_CBC
;
1234 } else if (strcmp(cp
, "des") == 0)
1235 *alg
= SEC_OID_DES_CBC
;
1236 else if (strcmp(cp
, "fortezza") == 0)
1237 *alg
= SEC_OID_FORTEZZA_SKIPJACK
;
1238 else if (strcmp(cp
, "des-ede3") == 0)
1241 fprintf(stderr
, "Invalid cipher \"%s\".\n", cp
);
1248 #endif /* USE_NSS */