2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
8 * Changes Copyright (c) 2004
9 * Gunnar Ritter. All rights reserved.
12 * Parts of this file are derived from the Mozilla NSS 3.9.2 source,
13 * mozilla/security/nss/cmd/smimetools/cmsutil.c. Therefore:
15 * The contents of this file are subject to the Mozilla Public License
16 * Version 1.1 (the "License"); you may not use this file except in
17 * compliance with the License. You may obtain a copy of the License
18 * at http://www.mozilla.org/MPL/
20 * Software distributed under the License is distributed on an "AS
21 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
22 * implied. See the License for the specific language governing
23 * rights and limitations under the License.
25 * The Original Code is the Netscape security libraries.
27 * The Initial Developer of the Original Code is Netscape
28 * Communications Corporation. Portions created by Netscape are
29 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
37 static char sccsid
[] = "@(#)nss.c 1.48 (gritter) 8/4/07";
44 typedef int avoid_empty_file_compiler_warning
;
55 static struct termios otio
;
56 static sigjmp_buf nssjmp
;
76 #include <private/pprio.h>
80 #ifndef HAVE_CERTAltNameEncodedContext
82 * NSS 3.11.5 neither installs genname.h nor provides this
83 * structure otherwise, so define it here.
85 typedef struct CERTAltNameEncodedContextStr
{
86 SECItem
**encodedGenName
;
87 } CERTAltNameEncodedContext
;
88 #endif /* !HAVE_CERTAltNameEncodedContext */
92 static char *password_cb(PK11SlotInfo
*slot
, PRBool retry
, void *arg
);
93 static SECStatus
bad_cert_cb(void *arg
, PRFileDesc
*fd
);
94 static enum okay
nss_check_host(const char *server
, struct sock
*sp
);
95 static const char *bad_cert_str(void);
96 static enum okay
nss_init(void);
97 static void nss_select_method(const char *uhp
);
98 static CERTCertificate
*get_signer_cert(char *addr
);
99 static FILE *encode(FILE *ip
, FILE **hp
, FILE **bp
, NSSCMSMessage
*msg
,
100 void (*cb
)(void *, const char *, unsigned long));
101 static void decoder_cb(void *arg
, const char *buf
, unsigned long len
);
102 static void base64_cb(void *arg
, const char *buf
, unsigned long len
);
103 static int verify1(struct message
*m
, int n
);
104 static struct message
*getsig(struct message
*m
, int n
, NSSCMSMessage
**msg
);
105 static enum okay
getdig(struct message
*m
, int n
, SECItem
***digests
,
106 PLArenaPool
**poolp
, SECAlgorithmID
**algids
);
107 static void nsscatch(int s
);
108 static void dumpcert(CERTCertificate
*cert
, FILE *op
);
109 static enum okay
getcipher(const char *to
, SECOidTag
*alg
, int *key
);
112 password_cb(PK11SlotInfo
*slot
, PRBool retry
, void *arg
)
114 sighandler_type saveint
;
119 saveint
= safe_signal(SIGINT
, SIG_IGN
);
120 if (sigsetjmp(nssjmp
, 1) == 0) {
121 if (saveint
!= SIG_IGN
)
122 safe_signal(SIGINT
, nsscatch
);
123 pass
= getpassword(&otio
, &reset_tio
, arg
);
125 safe_signal(SIGINT
, saveint
);
128 return PL_strdup(pass
);
132 bad_cert_cb(void *arg
, PRFileDesc
*fd
)
134 if (PORT_GetError() == SSL_ERROR_BAD_CERT_DOMAIN
)
136 * We must not use this result. NSS verifies host names
137 * according to RFC 2818, but we must verify host names
138 * according to RFC 2595. The rules are different:
140 * - RFC 2818 says that if both a dNSName and a CN are
141 * contained in the peer certificate, only the dNSName
142 * is used. RFC 2595 encourages to use both.
144 * - RFC 2818 allows the wildcard '*' in any component
145 * of the host name. RFC 2595 allows it only as the
146 * "left-most name component".
148 * So ignore it and verify separately.
151 fprintf(stderr
, "Error in certificate: %s.\n", bad_cert_str());
152 return ssl_vrfy_decide() == OKAY
? SECSuccess
: SECFailure
;
156 * Host name checking according to RFC 2595.
159 nss_check_host(const char *server
, struct sock
*sp
)
161 CERTCertificate
*cert
;
167 CERTAltNameEncodedContext ec
;
169 const SEC_ASN1Template gntempl
[] = {
170 { SEC_ASN1_SEQUENCE_OF
, 0, SEC_AnyTemplate
}
173 if ((cert
= SSL_PeerCertificate(sp
->s_prfd
)) == NULL
) {
174 fprintf(stderr
, "no certificate from \"%s\"\n", server
);
177 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
178 if (CERT_FindCertExtension(cert
, SEC_OID_X509_SUBJECT_ALT_NAME
,
179 &altname
) == SECSuccess
&&
180 SEC_ASN1DecodeItem(arena
, &ec
, gntempl
,
181 &altname
) == SECSuccess
&&
182 ec
.encodedGenName
!= NULL
) {
183 for (i
= 0; ec
.encodedGenName
[i
] != NULL
; i
++) {
184 gn
= CERT_DecodeGeneralName(arena
, ec
.encodedGenName
[i
],
186 if (gn
->type
== certDNSName
) {
187 char *dn
= ac_alloc(gn
->name
.other
.len
+ 1);
188 memcpy(dn
, gn
->name
.other
.data
,
190 dn
[gn
->name
.other
.len
] = '\0';
193 "Comparing DNS name: \"%s\"\n",
195 if (rfc2595_hostname_match(server
, dn
)
204 if ((cn
= CERT_GetCommonName(&cert
->subject
)) != NULL
) {
206 fprintf(stderr
, "Comparing common name: \"%s\"\n", cn
);
207 ok
= rfc2595_hostname_match(server
, cn
);
210 fprintf(stderr
, "host certificate does not match \"%s\"\n",
214 PORT_FreeArena(arena
, PR_FALSE
);
215 CERT_DestroyCertificate(cert
);
224 ec
= PORT_GetError();
225 return nss_strerror(ec
);
231 static int initialized
;
234 verbose
= value("verbose") != NULL
;
235 if (initialized
== 0) {
236 if ((cp
= value("nss-config-dir")) == NULL
) {
237 fputs("Missing \"nss-config-dir\" variable.\n", stderr
);
242 PK11_SetPasswordFunc(password_cb
);
243 if (NSS_Init(cp
) == SECSuccess
) {
244 NSS_SetDomesticPolicy();
248 nss_gen_err("Error initializing NSS");
255 nss_select_method(const char *uhp
)
264 methods
= SSL2
|SSL3
|TLS1
;
265 cp
= ssl_method_string(uhp
);
267 if (equal(cp
, "ssl2"))
269 else if (equal(cp
, "ssl3"))
271 else if (equal(cp
, "tls1"))
274 fprintf(stderr
, catgets(catd
, CATSET
, 244,
275 "Invalid SSL method \"%s\"\n"), cp
);
278 if (value("ssl-v2-allow") == NULL
)
280 SSL_OptionSetDefault(SSL_ENABLE_SSL2
, methods
&SSL2
? PR_TRUE
:PR_FALSE
);
281 SSL_OptionSetDefault(SSL_ENABLE_SSL3
, methods
&SSL3
? PR_TRUE
:PR_FALSE
);
282 SSL_OptionSetDefault(SSL_ENABLE_TLS
, methods
&TLS1
? PR_TRUE
:PR_FALSE
);
286 ssl_open(const char *server
, struct sock
*sp
, const char *uhp
)
288 PRFileDesc
*fdp
, *fdc
;
290 if (nss_init() == STOP
)
292 ssl_set_vrfy_level(uhp
);
293 nss_select_method(uhp
);
294 if ((fdp
= PR_ImportTCPSocket(sp
->s_fd
)) == NULL
) {
295 nss_gen_err("Error importing OS file descriptor");
298 if ((fdc
= SSL_ImportFD(NULL
, fdp
)) == NULL
) {
299 nss_gen_err("Error importing NSPR file descriptor");
303 SSL_SetURL(fdc
, server
);
304 SSL_SetPKCS11PinArg(fdc
, NULL
);
305 SSL_BadCertHook(fdc
, bad_cert_cb
, NULL
);
306 if (SSL_ResetHandshake(fdc
, PR_FALSE
) != SECSuccess
) {
307 nss_gen_err("Cannot reset NSS handshake");
311 if (SSL_ForceHandshake(fdc
) != 0) {
312 nss_gen_err("SSL/TLS handshake failed");
317 if (nss_check_host(server
, sp
) != OKAY
&& ssl_vrfy_decide() != OKAY
) {
324 char *cipher
, *issuer
, *subject
;
325 int keysize
, secretkeysize
;
327 if (SSL_SecurityStatus(fdc
, NULL
, &cipher
,
328 &keysize
, &secretkeysize
,
329 &issuer
, &subject
) == SECSuccess
) {
330 fprintf(stderr
, "SSL parameters: cipher=%s, "
331 "keysize=%d, secretkeysize=%d,\n"
334 cipher
, keysize
, secretkeysize
,
340 nss_gen_err("Could not read status information");
346 nss_gen_err(const char *fmt
, ...)
353 vfprintf(stderr
, fmt
, ap
);
355 if ((len
= PR_GetErrorTextLength()) > 0) {
356 text
= ac_alloc(len
);
357 if (PR_GetErrorText(text
) > 0)
358 fprintf(stderr
, ": %s\n", text
);
361 fprintf(stderr
, ": %s.\n", nss_strerror(PR_GetError()));
365 smime_sign(FILE *ip
, struct header
*headp
)
368 NSSCMSContentInfo
*content
;
369 NSSCMSSignedData
*data
;
370 NSSCMSSignerInfo
*info
;
371 CERTCertificate
*cert
;
372 CERTCertDBHandle
*handle
;
376 if (nss_init() != OKAY
)
378 if ((addr
= myorigin(headp
)) == NULL
) {
379 fprintf(stderr
, "No \"from\" address for signing specified\n");
382 if ((cert
= get_signer_cert(addr
)) == NULL
)
384 handle
= CERT_GetDefaultCertDB();
385 if ((msg
= NSS_CMSMessage_Create(NULL
)) == NULL
) {
386 fprintf(stderr
, "Cannot create CMS message.\n");
389 if ((data
= NSS_CMSSignedData_Create(msg
)) == NULL
) {
390 fprintf(stderr
, "Cannot create CMS signed data.\n");
393 content
= NSS_CMSMessage_GetContentInfo(msg
);
394 if (NSS_CMSContentInfo_SetContent_SignedData(msg
, content
, data
)
396 fprintf(stderr
, "Cannot attach CMS signed data.\n");
399 content
= NSS_CMSSignedData_GetContentInfo(data
);
400 if (NSS_CMSContentInfo_SetContent_Data(msg
, content
, NULL
, PR_TRUE
)
402 fprintf(stderr
, "Cannot attach CMS data.\n");
405 if ((info
= NSS_CMSSignerInfo_Create(msg
, cert
, SEC_OID_SHA1
)) == 0) {
406 fprintf(stderr
, "Cannot create signed information.\n");
409 if (NSS_CMSSignerInfo_IncludeCerts(info
, NSSCMSCM_CertOnly
,
410 certUsageEmailSigner
) != SECSuccess
) {
411 fprintf(stderr
, "Cannot include certificate.\n");
414 if (NSS_CMSSignerInfo_AddSigningTime(info
, PR_Now()) != SECSuccess
) {
415 fprintf(stderr
, "Cannot add signing time.\n");
418 if (NSS_CMSSignerInfo_AddSMIMECaps(info
) != SECSuccess
) {
419 fprintf(stderr
, "Cannot add S/MIME capabilities.\n");
422 NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(info
, cert
, handle
);
423 NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(info
, cert
, handle
);
424 if (NSS_CMSSignedData_AddCertificate(data
, cert
) != SECSuccess
) {
425 fprintf(stderr
, "Cannot add encryption certificate.\n");
428 if (NSS_CMSSignedData_AddSignerInfo(data
, info
) != SECSuccess
) {
429 fprintf(stderr
, "Cannot add signer information.\n");
432 CERT_DestroyCertificate(cert
);
433 if ((sp
= encode(ip
, &hp
, &bp
, msg
, base64_cb
)) == NULL
) {
434 NSS_CMSMessage_Destroy(msg
);
437 NSS_CMSMessage_Destroy(msg
);
438 return smime_sign_assemble(hp
, bp
, sp
);
444 int *msgvec
= vp
, *ip
;
447 if (nss_init() != OKAY
)
449 ssl_vrfy_level
= VRFY_STRICT
;
450 for (ip
= msgvec
; *ip
; ip
++) {
451 setdot(&message
[*ip
-1]);
452 ec
|= verify1(&message
[*ip
-1], *ip
);
458 smime_encrypt(FILE *ip
, const char *ignored
, const char *to
)
461 NSSCMSContentInfo
*content
;
462 NSSCMSEnvelopedData
*data
;
463 NSSCMSRecipientInfo
*info
;
464 CERTCertificate
*cert
[2];
465 CERTCertDBHandle
*handle
;
472 if (nss_init() != OKAY
)
474 handle
= CERT_GetDefaultCertDB();
475 vn
= ac_alloc(vs
= strlen(to
) + 30);
476 snprintf(vn
, vs
, "smime-nickname-%s", to
);
477 nickname
= value(vn
);
479 if ((cert
[0] = CERT_FindCertByNicknameOrEmailAddr(handle
,
480 nickname
? nickname
: (char *)to
)) == NULL
) {
482 fprintf(stderr
, "Cannot find certificate \"%s\".\n",
485 fprintf(stderr
, "Cannot find certificate for <%s>.\n",
490 if (getcipher(to
, &tag
, &keysize
) != OKAY
)
492 if ((msg
= NSS_CMSMessage_Create(NULL
)) == NULL
) {
493 fprintf(stderr
, "Cannot create CMS message.\n");
496 if ((data
= NSS_CMSEnvelopedData_Create(msg
, tag
, keysize
)) == NULL
) {
497 fprintf(stderr
, "Cannot create enveloped data.\n");
500 content
= NSS_CMSMessage_GetContentInfo(msg
);
501 if (NSS_CMSContentInfo_SetContent_EnvelopedData(msg
, content
, data
)
503 fprintf(stderr
, "Cannot attach enveloped data.\n");
506 content
= NSS_CMSEnvelopedData_GetContentInfo(data
);
507 if (NSS_CMSContentInfo_SetContent_Data(msg
, content
, NULL
, PR_FALSE
)
509 fprintf(stderr
, "Cannot attach CMS data.\n");
512 if ((info
= NSS_CMSRecipientInfo_Create(msg
, cert
[0])) == NULL
) {
513 fprintf(stderr
, "Cannot create CMS recipient information.\n");
516 if (NSS_CMSEnvelopedData_AddRecipient(data
, info
) != SECSuccess
) {
517 fprintf(stderr
, "Cannot add CMS recipient information.\n");
520 CERT_DestroyCertificate(cert
[0]);
521 if ((yp
= encode(ip
, &hp
, &pp
, msg
, base64_cb
)) == NULL
)
523 NSS_CMSMessage_Destroy(msg
);
524 return smime_encrypt_assemble(hp
, yp
);
528 smime_decrypt(struct message
*m
, const char *to
, const char *cc
, int signcall
)
530 NSSCMSDecoderContext
*ctx
;
534 size_t bufsize
= 0, buflen
, count
;
542 if ((yp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
)
544 if (nss_init() != OKAY
)
546 if ((op
= Ftemp(&cp
, "Rp", "w+", 0600, 1)) == NULL
) {
552 if ((ctx
= NSS_CMSDecoder_Start(NULL
,
554 password_cb
, "Pass phrase:",
555 NULL
, NULL
)) == NULL
) {
556 fprintf(stderr
, "Cannot start decoder.\n");
560 if ((smime_split(yp
, &hp
, &bp
, size
, 1)) == STOP
)
563 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, bp
, 0) != NULL
) {
566 if ((cp
= thisfield(buf
, "content-transfer-encoding")) != NULL
)
567 if (ascncasecmp(cp
, "binary", 7) == 0)
570 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, bp
, 0) != NULL
) {
572 NSS_CMSDecoder_Update(ctx
, buf
, buflen
);
576 mime_fromb64_b(&in
, &out
, 0, bp
);
577 NSS_CMSDecoder_Update(ctx
, out
.s
, out
.l
);
582 if ((msg
= NSS_CMSDecoder_Finish(ctx
)) == NULL
) {
583 fprintf(stderr
, "Failed to decode message.\n");
588 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
589 for (i
= 0; i
< nlevels
; i
++) {
590 NSSCMSContentInfo
*content
;
593 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
594 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
595 if (tag
== SEC_OID_PKCS7_DATA
) {
596 const char *fld
= "X-Encryption-Cipher";
600 alg
= NSS_CMSContentInfo_GetContentEncAlgTag(content
);
601 keysize
= NSS_CMSContentInfo_GetBulkKeySize(content
);
602 fseek(hp
, 0L, SEEK_END
);
606 NSS_CMSMessage_Destroy(msg
);
609 setinput(&mb
, m
, NEED_BODY
);
610 return (struct message
*)-1;
612 fprintf(hp
, "%s: none\n", fld
);
614 case SEC_OID_RC2_CBC
:
615 fprintf(hp
, "%s: RC2, %d bits\n", fld
, keysize
);
617 case SEC_OID_DES_CBC
:
618 fprintf(hp
, "%s: DES, 56 bits\n", fld
);
620 case SEC_OID_DES_EDE3_CBC
:
621 fprintf(hp
, "%s: 3DES, 112/168 bits\n", fld
);
623 case SEC_OID_FORTEZZA_SKIPJACK
:
624 fprintf(hp
, "%s: Fortezza\n", fld
);
627 fprintf(hp
, "%s: unknown type %lu\n", fld
,
634 NSS_CMSMessage_Destroy(msg
);
638 return smime_decrypt_assemble(m
, hp
, op
);
641 static CERTCertificate
*
642 get_signer_cert(char *addr
)
644 CERTCertDBHandle
*handle
;
646 CERTCertListNode
*node
;
647 CERTCertificate
*cert
= NULL
;
654 vn
= ac_alloc(vs
= strlen(addr
) + 30);
655 snprintf(vn
, vs
, "smime-sign-nickname-%s", addr
);
656 if ((nick
= value(vn
)) == NULL
)
657 nick
= value("smime-sign-nickname");
659 handle
= CERT_GetDefaultCertDB();
661 cert
= CERT_FindCertByNickname(handle
, nick
);
663 fprintf(stderr
, "No certificate \"%s\" found.\n", nick
);
666 if ((list
= CERT_FindUserCertsByUsage(handle
, certUsageEmailSigner
,
667 PR_TRUE
, PR_TRUE
, NULL
)) == NULL
) {
668 fprintf(stderr
, "Cannot find any certificates for signing.\n");
671 for (node
= CERT_LIST_HEAD(list
); !CERT_LIST_END(node
, list
);
672 node
= CERT_LIST_NEXT(node
)) {
673 if ((cp
= CERT_GetCertEmailAddress(&node
->cert
->subject
))
674 != NULL
&& asccasecmp(cp
, addr
) == 0) {
680 for (node
= CERT_LIST_HEAD(list
);
681 !CERT_LIST_END(node
, list
) && cert
== NULL
;
682 node
= CERT_LIST_NEXT(node
)) {
683 cp
= CERT_GetFirstEmailAddress(node
->cert
);
685 if (asccasecmp(cp
, addr
) == 0) {
689 cp
= CERT_GetNextEmailAddress(node
->cert
, cp
);
695 "More than one signing certificate found for <%s>.\n"
696 "Use the smime-sign-nickname variable.\n", addr
);
701 "Cannot find a signing certificate for <%s>.\n",
707 encode(FILE *ip
, FILE **hp
, FILE **bp
, NSSCMSMessage
*msg
,
708 void (*cb
)(void *, const char *, unsigned long))
710 NSSCMSEncoderContext
*ctx
;
711 char *buf
= NULL
, *cp
;
712 size_t bufsize
= 0, buflen
, count
;
715 if (smime_split(ip
, hp
, bp
, -1, 0) == STOP
)
717 if ((op
= Ftemp(&cp
, "Ry", "w+", 0600, 1)) == NULL
) {
723 if ((ctx
= NSS_CMSEncoder_Start(msg
,
726 password_cb
, "Pass phrase:",
728 NULL
, NULL
)) == NULL
) {
729 fprintf(stderr
, "Cannot create encoder context.\n");
734 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, *bp
, 0) != NULL
) {
735 buf
[buflen
-1] = '\r';
737 if (NSS_CMSEncoder_Update(ctx
, buf
, buflen
+1) != 0) {
738 fprintf(stderr
, "Failed to add data to encoder.\n");
744 if (NSS_CMSEncoder_Finish(ctx
) != 0) {
745 fprintf(stderr
, "Failed to encode data.\n");
750 cb(op
, (void *)-1, 0);
762 decoder_cb(void *arg
, const char *buf
, unsigned long len
)
765 fwrite(buf
, 1, len
, arg
);
769 base64_cb(void *arg
, const char *buf
, unsigned long len
)
771 static char back
[972];
775 if (arg
&& buf
&& buf
!= (void *)-1) {
777 while (len
- pos
>= sizeof back
- fill
) {
778 memcpy(&back
[fill
], &buf
[pos
], sizeof back
- fill
);
779 mime_write(back
, sizeof back
, arg
,
780 CONV_TOB64
, TD_NONE
, NULL
, 0,
782 pos
+= sizeof back
- fill
;
785 memcpy(&back
[fill
], &buf
[pos
], len
- pos
);
787 } else if (buf
== (void *)-1) {
788 mime_write(back
, fill
, arg
,
789 CONV_TOB64
, TD_NONE
, NULL
, 0,
796 verify1(struct message
*m
, int n
)
801 SECAlgorithmID
**algids
;
802 CERTCertDBHandle
*handle
;
808 if ((m
= getsig(m
, n
, &msg
)) == NULL
)
810 sender
= getsender(m
);
811 handle
= CERT_GetDefaultCertDB();
812 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
813 for (i
= 0; i
< nlevels
; i
++) {
814 NSSCMSContentInfo
*content
;
817 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
818 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
819 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
820 NSSCMSSignedData
*data
;
823 if ((data
= NSS_CMSContentInfo_GetContent(content
))
825 fprintf(stderr
, "Signed data missing for "
830 if (!NSS_CMSSignedData_HasDigests(data
)) {
831 algids
= NSS_CMSSignedData_GetDigestAlgs(data
);
832 if (getdig(m
, n
, &digests
, &poolp
, algids
)
837 if (NSS_CMSSignedData_SetDigests(data
, algids
,
840 fprintf(stderr
, "Cannot set digests "
841 "for message %d.\n", n
);
845 PORT_FreeArena(poolp
, PR_FALSE
);
847 if (NSS_CMSSignedData_ImportCerts(data
, handle
,
848 certUsageEmailSigner
,
849 PR_FALSE
) != SECSuccess
) {
850 fprintf(stderr
, "Cannot temporarily import "
856 nsigners
= NSS_CMSSignedData_SignerInfoCount(data
);
858 fprintf(stderr
, "Message %d has no signers.\n",
863 if (!NSS_CMSSignedData_HasDigests(data
)) {
864 fprintf(stderr
, "Message %d has no digests.\n",
869 for (j
= 0; j
< nsigners
; j
++) {
871 NSSCMSSignerInfo
*info
;
872 NSSCMSVerificationStatus vs
;
874 CERTCertificate
*cert
;
878 info
= NSS_CMSSignedData_GetSignerInfo(data
, j
);
879 cert
= NSS_CMSSignerInfo_GetSigningCertificate
881 bad
= NSS_CMSSignedData_VerifySignerInfo(data
,
883 certUsageEmailSigner
);
884 vs
= NSS_CMSSignerInfo_GetVerificationStatus
886 svs
= NSS_CMSUtil_VerificationStatusToString
888 addr
= CERT_GetCertEmailAddress(&cert
->subject
);
889 if (sender
!= NULL
&& addr
!= NULL
&&
890 asccasecmp(sender
, addr
) == 0)
893 addr
= CERT_GetFirstEmailAddress(cert
);
894 while (sender
&& addr
) {
895 if (!asccasecmp(sender
, addr
)) {
899 addr
= CERT_GetNextEmailAddress
903 if (CERT_VerifyCertNow(handle
,
905 certUsageEmailSigner
,
907 fprintf(stderr
, "Bad certificate for "
910 addr
? addr
: "?", n
,
915 fprintf(stderr
, "Bad status for "
924 else if (status
== 0)
929 if (foundsender
== 0) {
931 fprintf(stderr
, "Signers of message "
932 "%d do not include the sender <%s>\n",
936 fprintf(stderr
, "Warning: Message %d has no From: "
937 "header field.\n", n
);
938 } else if (status
== 1)
939 printf("Message %d was verified successfully.\n", n
);
941 fprintf(stderr
, "No verification information found in "
943 NSS_CMSMessage_Destroy(msg
);
947 static struct message
*
948 getsig(struct message
*m
, int n
, NSSCMSMessage
**msg
)
951 char *ct
, *pt
, *boundary
= NULL
, *cte
;
953 size_t bufsize
= 0, buflen
, count
, boundlen
= -1;
956 NSSCMSDecoderContext
*decctx
;
962 loop
: if ((ct
= hfield("content-type", m
)) == NULL
)
964 if (strncmp(ct
, "application/x-pkcs7-mime", 24) == 0 ||
965 strncmp(ct
, "application/pkcs7-mime", 22) == 0) {
966 to
= hfield("to", m
);
967 cc
= hfield("cc", m
);
968 if ((x
= smime_decrypt(m
, to
, cc
, 1)) == NULL
)
970 if (x
!= (struct message
*)-1) {
975 } else if (strncmp(ct
, "multipart/signed", 16) ||
976 (pt
= mime_getparam("protocol", ct
)) == NULL
||
977 strcmp(pt
, "application/x-pkcs7-signature") &&
978 strcmp(pt
, "application/pkcs7-signature") ||
979 (boundary
= mime_getboundary(ct
)) == NULL
) {
981 "Message %d is not an S/MIME signed message.\n", n
);
984 boundlen
= strlen(boundary
);
985 if ((decctx
= NSS_CMSDecoder_Start(NULL
, NULL
, NULL
,
986 password_cb
, "Pass phrase:",
987 NULL
, NULL
)) == NULL
) {
988 fprintf(stderr
, "Cannot start decoder.\n");
991 if ((fp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
) {
998 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, fp
, 0) != NULL
) {
999 if (detached
&& boundary
&& buflen
>= boundlen
+ 1 &&
1000 strncmp(buf
, boundary
, boundlen
) == 0) {
1001 if (buf
[boundlen
] == '\n') {
1006 fprintf(stderr
, "Message %d has too "
1007 "many parts.\n", n
);
1013 if (buf
[boundlen
] == '-' && buf
[boundlen
+1] == '-' &&
1014 buf
[boundlen
+2] == '\n')
1016 } else if (buf
[0] == '\n') {
1020 if ((!detached
|| part
== 2) && inhdr
== 0) {
1022 NSS_CMSDecoder_Update(decctx
, buf
, buflen
);
1026 mime_fromb64_b(&in
, &out
, 0, fp
);
1027 NSS_CMSDecoder_Update(decctx
, out
.s
, out
.l
);
1031 if (buflen
== 1 && buf
[0] == '\n')
1033 if (inhdr
&& (cte
= thisfield(buf
, "content-transfer-encoding"))
1034 != NULL
&& ascncasecmp(cte
, "binary", 7) == 0)
1038 if ((*msg
= NSS_CMSDecoder_Finish(decctx
)) == NULL
) {
1039 fprintf(stderr
, "Failed to decode signature for message %d.\n",
1047 getdig(struct message
*m
, int n
, SECItem
***digests
,
1048 PLArenaPool
**poolp
, SECAlgorithmID
**algids
)
1050 char *ct
, *pt
, *boundary
;
1052 size_t bufsize
= 0, buflen
, count
, boundlen
;
1056 NSSCMSDigestContext
*digctx
;
1058 *poolp
= PORT_NewArena(1024);
1059 if ((ct
= hfield("content-type", m
)) == NULL
||
1060 strncmp(ct
, "multipart/signed", 16) ||
1061 (pt
= mime_getparam("protocol", ct
)) == NULL
||
1062 strcmp(pt
, "application/x-pkcs7-signature") &&
1063 strcmp(pt
, "application/pkcs7-signature") ||
1064 (boundary
= mime_getboundary(ct
)) == NULL
) {
1066 "Message %d is not an S/MIME signed message.\n", n
);
1069 boundlen
= strlen(boundary
);
1070 if ((digctx
= NSS_CMSDigestContext_StartMultiple(algids
)) == NULL
) {
1071 fprintf(stderr
, "Cannot start digest computation.\n");
1074 if ((fp
= setinput(&mb
, m
, NEED_BODY
)) == NULL
) {
1080 while (fgetline(&buf
, &bufsize
, &count
, &buflen
, fp
, 0) != NULL
) {
1081 if (buflen
>= boundlen
+ 1 &&
1082 strncmp(buf
, boundary
, boundlen
) == 0) {
1083 if (buf
[boundlen
] == '\n') {
1088 if (buf
[boundlen
] == '-' && buf
[boundlen
+1] == '-' &&
1089 buf
[boundlen
+2] == '\n')
1094 NSS_CMSDigestContext_Update(digctx
,
1095 (unsigned char *)"\r\n", 2);
1098 if (buf
[buflen
-1] == '\n') {
1102 NSS_CMSDigestContext_Update(digctx
,
1103 (unsigned char *)buf
, buflen
);
1108 if (NSS_CMSDigestContext_FinishMultiple(digctx
,
1109 *poolp
, digests
) != SECSuccess
) {
1110 fprintf(stderr
, "Error creating digest for message %d\n", n
);
1120 tcsetattr(0, TCSADRAIN
, &otio
);
1121 siglongjmp(nssjmp
, s
);
1125 smime_certsave(struct message
*m
, int n
, FILE *op
)
1128 CERTCertDBHandle
*handle
;
1129 int nlevels
, i
, cnt
= 0;
1130 enum okay ok
= OKAY
;
1132 if (nss_init() == STOP
)
1134 if ((m
= getsig(m
, n
, &msg
)) == NULL
)
1136 handle
= CERT_GetDefaultCertDB();
1137 nlevels
= NSS_CMSMessage_ContentLevelCount(msg
);
1138 for (i
= 0; i
< nlevels
; i
++) {
1139 NSSCMSContentInfo
*content
;
1142 content
= NSS_CMSMessage_ContentLevel(msg
, i
);
1143 tag
= NSS_CMSContentInfo_GetContentTypeTag(content
);
1144 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
1145 NSSCMSSignedData
*data
;
1148 if ((data
= NSS_CMSContentInfo_GetContent(content
))
1150 fprintf(stderr
, "Signed data missing for "
1151 "message %d.\n", n
);
1155 if (NSS_CMSSignedData_ImportCerts(data
, handle
,
1156 certUsageEmailSigner
,
1157 PR_FALSE
) != SECSuccess
) {
1158 fprintf(stderr
, "Cannot temporarily import "
1160 "message %d.\n", n
);
1164 nsigners
= NSS_CMSSignedData_SignerInfoCount(data
);
1165 if (nsigners
== 0) {
1166 fprintf(stderr
, "Message %d has no signers.\n",
1171 for (j
= 0; j
< nsigners
; j
++) {
1172 NSSCMSSignerInfo
*info
;
1173 CERTCertificateList
*list
;
1174 CERTCertificate
*cert
;
1177 info
= NSS_CMSSignedData_GetSignerInfo(data
, j
);
1178 list
= NSS_CMSSignerInfo_GetCertList(info
);
1180 for (k
= 0; k
< list
->len
; k
++) {
1181 cert
= (CERTCertificate
*)
1187 cert
= NSS_CMSSignerInfo_GetSigningCertificate
1196 NSS_CMSMessage_Destroy(msg
);
1198 fprintf(stderr
, "No certificates found in message %d.\n", n
);
1205 dumpcert(CERTCertificate
*cert
, FILE *op
)
1207 fprintf(op
, "subject=%s\n", cert
->subjectName
);
1208 fprintf(op
, "issuer=%s\n", cert
->issuerName
);
1209 fputs("-----BEGIN CERTIFICATE-----\n", op
);
1210 mime_write(cert
->derCert
.data
,
1211 cert
->derCert
.len
, op
,
1212 CONV_TOB64
, TD_NONE
, NULL
, 0,
1214 fputs("-----END CERTIFICATE-----\n", op
);
1218 getcipher(const char *to
, SECOidTag
*alg
, int *key
)
1224 *alg
= SEC_OID_DES_EDE3_CBC
;
1225 vn
= ac_alloc(vs
= strlen(to
) + 30);
1226 snprintf(vn
, vs
, "smime-cipher-%s", to
);
1227 if ((cp
= value(vn
)) != NULL
) {
1228 if (strcmp(cp
, "rc2-40") == 0) {
1229 *alg
= SEC_OID_RC2_CBC
;
1231 } else if (strcmp(cp
, "rc2-64") == 0) {
1232 *alg
= SEC_OID_RC2_CBC
;
1234 } else if (strcmp(cp
, "rc2-128") == 0) {
1235 *alg
= SEC_OID_RC2_CBC
;
1237 } else if (strcmp(cp
, "des") == 0)
1238 *alg
= SEC_OID_DES_CBC
;
1239 else if (strcmp(cp
, "fortezza") == 0)
1240 *alg
= SEC_OID_FORTEZZA_SKIPJACK
;
1241 else if (strcmp(cp
, "des-ede3") == 0)
1244 fprintf(stderr
, "Invalid cipher \"%s\".\n", cp
);
1251 #endif /* USE_NSS */