OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 /* | 5 /* |
6 * Stuff specific to S/MIME policy and interoperability. | 6 * Stuff specific to S/MIME policy and interoperability. |
7 */ | 7 */ |
8 | 8 |
9 #include "secmime.h" | 9 #include "secmime.h" |
10 #include "secoid.h" | 10 #include "secoid.h" |
11 #include "pk11func.h" | 11 #include "pk11func.h" |
12 #include "ciferfam.h"» /* for CIPHER_FAMILY symbols */ | 12 #include "ciferfam.h" /* for CIPHER_FAMILY symbols */ |
13 #include "secasn1.h" | 13 #include "secasn1.h" |
14 #include "secitem.h" | 14 #include "secitem.h" |
15 #include "cert.h" | 15 #include "cert.h" |
16 #include "key.h" | 16 #include "key.h" |
17 #include "secerr.h" | 17 #include "secerr.h" |
18 #include "cms.h" | 18 #include "cms.h" |
19 #include "nss.h" | 19 #include "nss.h" |
20 | 20 |
21 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) | 21 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) |
22 SEC_ASN1_MKSUB(SEC_OctetStringTemplate) | 22 SEC_ASN1_MKSUB(SEC_OctetStringTemplate) |
23 SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate) | 23 SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate) |
24 | 24 |
25 /* various integer's ASN.1 encoding */ | 25 /* various integer's ASN.1 encoding */ |
26 static unsigned char asn1_int40[] = { SEC_ASN1_INTEGER, 0x01, 0x28 }; | 26 static unsigned char asn1_int40[] = {SEC_ASN1_INTEGER, 0x01, 0x28}; |
27 static unsigned char asn1_int64[] = { SEC_ASN1_INTEGER, 0x01, 0x40 }; | 27 static unsigned char asn1_int64[] = {SEC_ASN1_INTEGER, 0x01, 0x40}; |
28 static unsigned char asn1_int128[] = { SEC_ASN1_INTEGER, 0x02, 0x00, 0x80 }; | 28 static unsigned char asn1_int128[] = {SEC_ASN1_INTEGER, 0x02, 0x00, 0x80}; |
29 | 29 |
30 /* RC2 algorithm parameters (used in smime_cipher_map) */ | 30 /* RC2 algorithm parameters (used in smime_cipher_map) */ |
31 static SECItem param_int40 = { siBuffer, asn1_int40, sizeof(asn1_int40) }; | 31 static SECItem param_int40 = {siBuffer, asn1_int40, sizeof(asn1_int40)}; |
32 static SECItem param_int64 = { siBuffer, asn1_int64, sizeof(asn1_int64) }; | 32 static SECItem param_int64 = {siBuffer, asn1_int64, sizeof(asn1_int64)}; |
33 static SECItem param_int128 = { siBuffer, asn1_int128, sizeof(asn1_int128) }; | 33 static SECItem param_int128 = {siBuffer, asn1_int128, sizeof(asn1_int128)}; |
34 | 34 |
35 /* | 35 /* |
36 * XXX Would like the "parameters" field to be a SECItem *, but the | 36 * XXX Would like the "parameters" field to be a SECItem *, but the |
37 * encoder is having trouble with optional pointers to an ANY. Maybe | 37 * encoder is having trouble with optional pointers to an ANY. Maybe |
38 * once that is fixed, can change this back... | 38 * once that is fixed, can change this back... |
39 */ | 39 */ |
40 typedef struct { | 40 typedef struct { |
41 SECItem capabilityID; | 41 SECItem capabilityID; |
42 SECItem parameters; | 42 SECItem parameters; |
43 long cipher;» » /* optimization */ | 43 long cipher; /* optimization */ |
44 } NSSSMIMECapability; | 44 } NSSSMIMECapability; |
45 | 45 |
46 static const SEC_ASN1Template NSSSMIMECapabilityTemplate[] = { | 46 static const SEC_ASN1Template NSSSMIMECapabilityTemplate[] = { |
47 { SEC_ASN1_SEQUENCE, | 47 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSSMIMECapability)}, |
48 » 0, NULL, sizeof(NSSSMIMECapability) }, | 48 {SEC_ASN1_OBJECT_ID, offsetof(NSSSMIMECapability, capabilityID), }, |
49 { SEC_ASN1_OBJECT_ID, | 49 {SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, |
50 » offsetof(NSSSMIMECapability,capabilityID), }, | 50 offsetof(NSSSMIMECapability, parameters), }, |
51 { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, | 51 {0, }}; |
52 » offsetof(NSSSMIMECapability,parameters), }, | |
53 { 0, } | |
54 }; | |
55 | 52 |
56 static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = { | 53 static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = { |
57 { SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate } | 54 {SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate}}; |
58 }; | 55 |
59 | 56 /* |
60 /* | 57 * NSSSMIMEEncryptionKeyPreference - if we find one of these, it needs to prompt |
61 * NSSSMIMEEncryptionKeyPreference - if we find one of these, it needs to prompt
us | 58 * us |
62 * to store this and only this certificate permanently for the sender email add
ress. | 59 * to store this and only this certificate permanently for the sender email |
| 60 * address. |
63 */ | 61 */ |
64 typedef enum { | 62 typedef enum { |
65 NSSSMIMEEncryptionKeyPref_IssuerSN, | 63 NSSSMIMEEncryptionKeyPref_IssuerSN, |
66 NSSSMIMEEncryptionKeyPref_RKeyID, | 64 NSSSMIMEEncryptionKeyPref_RKeyID, |
67 NSSSMIMEEncryptionKeyPref_SubjectKeyID | 65 NSSSMIMEEncryptionKeyPref_SubjectKeyID |
68 } NSSSMIMEEncryptionKeyPrefSelector; | 66 } NSSSMIMEEncryptionKeyPrefSelector; |
69 | 67 |
70 typedef struct { | 68 typedef struct { |
71 NSSSMIMEEncryptionKeyPrefSelector selector; | 69 NSSSMIMEEncryptionKeyPrefSelector selector; |
72 union { | 70 union { |
73 » CERTIssuerAndSN»» » *issuerAndSN; | 71 CERTIssuerAndSN *issuerAndSN; |
74 » NSSCMSRecipientKeyIdentifier» *recipientKeyID; | 72 NSSCMSRecipientKeyIdentifier *recipientKeyID; |
75 » SECItem»» » » *subjectKeyID; | 73 SECItem *subjectKeyID; |
76 } id; | 74 } id; |
77 } NSSSMIMEEncryptionKeyPreference; | 75 } NSSSMIMEEncryptionKeyPreference; |
78 | 76 |
79 extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[]; | 77 extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[]; |
80 | 78 |
81 static const SEC_ASN1Template smime_encryptionkeypref_template[] = { | 79 static const SEC_ASN1Template smime_encryptionkeypref_template[] = { |
82 { SEC_ASN1_CHOICE, | 80 {SEC_ASN1_CHOICE, offsetof(NSSSMIMEEncryptionKeyPreference, selector), |
83 » offsetof(NSSSMIMEEncryptionKeyPreference,selector), NULL, | 81 NULL, sizeof(NSSSMIMEEncryptionKeyPreference)}, |
84 » sizeof(NSSSMIMEEncryptionKeyPreference) }, | 82 {SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0 | |
85 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0 | 83 SEC_ASN1_CONSTRUCTED, |
86 | SEC_ASN1_CONSTRUCTED, | 84 offsetof(NSSSMIMEEncryptionKeyPreference, id.issuerAndSN), |
87 » offsetof(NSSSMIMEEncryptionKeyPreference,id.issuerAndSN), | 85 SEC_ASN1_SUB(CERT_IssuerAndSNTemplate), |
88 » SEC_ASN1_SUB(CERT_IssuerAndSNTemplate), | 86 NSSSMIMEEncryptionKeyPref_IssuerSN}, |
89 » NSSSMIMEEncryptionKeyPref_IssuerSN }, | 87 {SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED, |
90 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 1 | 88 offsetof(NSSSMIMEEncryptionKeyPreference, id.recipientKeyID), |
91 | SEC_ASN1_CONSTRUCTED, | 89 NSSCMSRecipientKeyIdentifierTemplate, |
92 » offsetof(NSSSMIMEEncryptionKeyPreference,id.recipientKeyID), | 90 NSSSMIMEEncryptionKeyPref_RKeyID}, |
93 » NSSCMSRecipientKeyIdentifierTemplate, | 91 {SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 | |
94 » NSSSMIMEEncryptionKeyPref_RKeyID }, | 92 SEC_ASN1_CONSTRUCTED, |
95 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 | 93 offsetof(NSSSMIMEEncryptionKeyPreference, id.subjectKeyID), |
96 | SEC_ASN1_CONSTRUCTED, | 94 SEC_ASN1_SUB(SEC_OctetStringTemplate), |
97 » offsetof(NSSSMIMEEncryptionKeyPreference,id.subjectKeyID), | 95 NSSSMIMEEncryptionKeyPref_SubjectKeyID}, |
98 » SEC_ASN1_SUB(SEC_OctetStringTemplate), | 96 {0, }}; |
99 » NSSSMIMEEncryptionKeyPref_SubjectKeyID }, | |
100 { 0, } | |
101 }; | |
102 | 97 |
103 /* smime_cipher_map - map of SMIME symmetric "ciphers" to algtag & parameters */ | 98 /* smime_cipher_map - map of SMIME symmetric "ciphers" to algtag & parameters */ |
104 typedef struct { | 99 typedef struct { |
105 unsigned long cipher; | 100 unsigned long cipher; |
106 SECOidTag algtag; | 101 SECOidTag algtag; |
107 SECItem *parms; | 102 SECItem *parms; |
108 PRBool enabled;» /* in the user's preferences */ | 103 PRBool enabled; /* in the user's preferences */ |
109 PRBool allowed;» /* per export policy */ | 104 PRBool allowed; /* per export policy */ |
110 } smime_cipher_map_entry; | 105 } smime_cipher_map_entry; |
111 | 106 |
112 /* global: list of supported SMIME symmetric ciphers, ordered roughly by increas
ing strength */ | 107 /* global: list of supported SMIME symmetric ciphers, ordered roughly by |
| 108 * increasing strength */ |
113 static smime_cipher_map_entry smime_cipher_map[] = { | 109 static smime_cipher_map_entry smime_cipher_map[] = { |
114 /* cipher» » » algtag» » » parms» » enabled
allowed */ | 110 /* cipher» » » algtag» » » parms |
115 /* --------------------------------------------------------------------------
-------- */ | 111 enabled allowed */ |
116 { SMIME_RC2_CBC_40,»» SEC_OID_RC2_CBC,» ¶m_int40,» PR_TRUE,
PR_TRUE }, | 112 /* ----------------------------------------------------------------------
------------ |
117 { SMIME_DES_CBC_56,»» SEC_OID_DES_CBC,» NULL,» » PR_TRUE,
PR_TRUE }, | 113 */ |
118 { SMIME_RC2_CBC_64,»» SEC_OID_RC2_CBC,» ¶m_int64,» PR_TRUE,
PR_TRUE }, | 114 {SMIME_RC2_CBC_40, SEC_OID_RC2_CBC, ¶m_int40, PR_TRUE, PR_TRUE}, |
119 { SMIME_RC2_CBC_128,» SEC_OID_RC2_CBC,» ¶m_int128,» PR_TRUE,
PR_TRUE }, | 115 {SMIME_DES_CBC_56, SEC_OID_DES_CBC, NULL, PR_TRUE, PR_TRUE}, |
120 { SMIME_DES_EDE3_168,» SEC_OID_DES_EDE3_CBC,» NULL,» » PR_TRUE,
PR_TRUE }, | 116 {SMIME_RC2_CBC_64, SEC_OID_RC2_CBC, ¶m_int64, PR_TRUE, PR_TRUE}, |
121 { SMIME_AES_CBC_128,» SEC_OID_AES_128_CBC,» NULL,» » PR_TRUE,
PR_TRUE }, | 117 {SMIME_RC2_CBC_128, SEC_OID_RC2_CBC, ¶m_int128, PR_TRUE, PR_TRUE}, |
122 { SMIME_AES_CBC_256,» SEC_OID_AES_256_CBC,» NULL,» » PR_TRUE,
PR_TRUE } | 118 {SMIME_DES_EDE3_168, SEC_OID_DES_EDE3_CBC, NULL, PR_TRUE, PR_TRUE}, |
123 }; | 119 {SMIME_AES_CBC_128, SEC_OID_AES_128_CBC, NULL, PR_TRUE, PR_TRUE}, |
124 static const int smime_cipher_map_count = sizeof(smime_cipher_map) / sizeof(smim
e_cipher_map_entry); | 120 {SMIME_AES_CBC_256, SEC_OID_AES_256_CBC, NULL, PR_TRUE, PR_TRUE}}; |
| 121 static const int smime_cipher_map_count = |
| 122 sizeof(smime_cipher_map) / sizeof(smime_cipher_map_entry); |
125 | 123 |
126 /* | 124 /* |
127 * smime_mapi_by_cipher - find index into smime_cipher_map by cipher | 125 * smime_mapi_by_cipher - find index into smime_cipher_map by cipher |
128 */ | 126 */ |
129 static int | 127 static int smime_mapi_by_cipher(unsigned long cipher) { |
130 smime_mapi_by_cipher(unsigned long cipher) | 128 int i; |
131 { | 129 |
132 int i; | 130 for (i = 0; i < smime_cipher_map_count; i++) { |
133 | 131 if (smime_cipher_map[i].cipher == cipher) return i; /* bingo */ |
134 for (i = 0; i < smime_cipher_map_count; i++) { | 132 } |
135 » if (smime_cipher_map[i].cipher == cipher) | 133 return -1; /* should not happen if we're consistent, right? */ |
136 » return i;» /* bingo */ | |
137 } | |
138 return -1;» » /* should not happen if we're consistent, right? */ | |
139 } | 134 } |
140 | 135 |
141 /* | 136 /* |
142 * NSS_SMIME_EnableCipher - this function locally records the user's preference | 137 * NSS_SMIME_EnableCipher - this function locally records the user's preference |
143 */ | 138 */ |
144 SECStatus | 139 SECStatus NSS_SMIMEUtil_EnableCipher(unsigned long which, PRBool on) { |
145 NSS_SMIMEUtil_EnableCipher(unsigned long which, PRBool on) | 140 unsigned long mask; |
146 { | 141 int mapi; |
147 unsigned long mask; | 142 |
148 int mapi; | 143 mask = which & CIPHER_FAMILYID_MASK; |
149 | 144 |
150 mask = which & CIPHER_FAMILYID_MASK; | 145 PORT_Assert(mask == CIPHER_FAMILYID_SMIME); |
151 | 146 if (mask != CIPHER_FAMILYID_SMIME) /* XXX set an error! */ |
152 PORT_Assert (mask == CIPHER_FAMILYID_SMIME); | 147 return SECFailure; |
153 if (mask != CIPHER_FAMILYID_SMIME) | 148 |
154 » /* XXX set an error! */ | 149 mapi = smime_mapi_by_cipher(which); |
155 » return SECFailure; | 150 if (mapi < 0) /* XXX set an error */ |
156 | 151 return SECFailure; |
157 mapi = smime_mapi_by_cipher(which); | 152 |
158 if (mapi < 0) | 153 /* do we try to turn on a forbidden cipher? */ |
159 » /* XXX set an error */ | 154 if (!smime_cipher_map[mapi].allowed && on) { |
160 » return SECFailure; | 155 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); |
161 | 156 return SECFailure; |
162 /* do we try to turn on a forbidden cipher? */ | 157 } |
163 if (!smime_cipher_map[mapi].allowed && on) { | 158 |
164 » PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM); | 159 if (smime_cipher_map[mapi].enabled != on) smime_cipher_map[mapi].enabled = on; |
165 » return SECFailure; | 160 |
166 } | 161 return SECSuccess; |
167 | 162 } |
168 if (smime_cipher_map[mapi].enabled != on) | |
169 » smime_cipher_map[mapi].enabled = on; | |
170 | |
171 return SECSuccess; | |
172 } | |
173 | |
174 | 163 |
175 /* | 164 /* |
176 * this function locally records the export policy | 165 * this function locally records the export policy |
177 */ | 166 */ |
178 SECStatus | 167 SECStatus NSS_SMIMEUtil_AllowCipher(unsigned long which, PRBool on) { |
179 NSS_SMIMEUtil_AllowCipher(unsigned long which, PRBool on) | 168 unsigned long mask; |
180 { | 169 int mapi; |
181 unsigned long mask; | 170 |
182 int mapi; | 171 mask = which & CIPHER_FAMILYID_MASK; |
183 | 172 |
184 mask = which & CIPHER_FAMILYID_MASK; | 173 PORT_Assert(mask == CIPHER_FAMILYID_SMIME); |
185 | 174 if (mask != CIPHER_FAMILYID_SMIME) /* XXX set an error! */ |
186 PORT_Assert (mask == CIPHER_FAMILYID_SMIME); | 175 return SECFailure; |
187 if (mask != CIPHER_FAMILYID_SMIME) | 176 |
188 » /* XXX set an error! */ | 177 mapi = smime_mapi_by_cipher(which); |
189 » return SECFailure; | 178 if (mapi < 0) /* XXX set an error */ |
190 | 179 return SECFailure; |
191 mapi = smime_mapi_by_cipher(which); | 180 |
192 if (mapi < 0) | 181 if (smime_cipher_map[mapi].allowed != on) smime_cipher_map[mapi].allowed = on; |
193 » /* XXX set an error */ | 182 |
194 » return SECFailure; | 183 return SECSuccess; |
195 | |
196 if (smime_cipher_map[mapi].allowed != on) | |
197 » smime_cipher_map[mapi].allowed = on; | |
198 | |
199 return SECSuccess; | |
200 } | 184 } |
201 | 185 |
202 /* | 186 /* |
203 * Based on the given algorithm (including its parameters, in some cases!) | 187 * Based on the given algorithm (including its parameters, in some cases!) |
204 * and the given key (may or may not be inspected, depending on the | 188 * and the given key (may or may not be inspected, depending on the |
205 * algorithm), find the appropriate policy algorithm specification | 189 * algorithm), find the appropriate policy algorithm specification |
206 * and return it. If no match can be made, -1 is returned. | 190 * and return it. If no match can be made, -1 is returned. |
207 */ | 191 */ |
208 static SECStatus | 192 static SECStatus nss_smime_get_cipher_for_alg_and_key(SECAlgorithmID *algid, |
209 nss_smime_get_cipher_for_alg_and_key(SECAlgorithmID *algid, PK11SymKey *key, uns
igned long *cipher) | 193 PK11SymKey *key, |
210 { | 194 unsigned long *cipher) { |
211 SECOidTag algtag; | 195 SECOidTag algtag; |
212 unsigned int keylen_bits; | 196 unsigned int keylen_bits; |
213 unsigned long c; | 197 unsigned long c; |
214 | 198 |
215 algtag = SECOID_GetAlgorithmTag(algid); | 199 algtag = SECOID_GetAlgorithmTag(algid); |
216 switch (algtag) { | 200 switch (algtag) { |
217 case SEC_OID_RC2_CBC: | 201 case SEC_OID_RC2_CBC: |
218 » keylen_bits = PK11_GetKeyStrength(key, algid); | 202 keylen_bits = PK11_GetKeyStrength(key, algid); |
219 » switch (keylen_bits) { | 203 switch (keylen_bits) { |
220 » case 40: | 204 case 40: |
221 » c = SMIME_RC2_CBC_40; | 205 c = SMIME_RC2_CBC_40; |
222 » break; | 206 break; |
223 » case 64: | 207 case 64: |
224 » c = SMIME_RC2_CBC_64; | 208 c = SMIME_RC2_CBC_64; |
225 » break; | 209 break; |
226 » case 128: | 210 case 128: |
227 » c = SMIME_RC2_CBC_128; | 211 c = SMIME_RC2_CBC_128; |
228 » break; | 212 break; |
229 » default: | 213 default: |
230 » return SECFailure; | 214 return SECFailure; |
231 » } | 215 } |
232 » break; | 216 break; |
233 case SEC_OID_DES_CBC: | 217 case SEC_OID_DES_CBC: |
234 » c = SMIME_DES_CBC_56; | 218 c = SMIME_DES_CBC_56; |
235 » break; | 219 break; |
236 case SEC_OID_DES_EDE3_CBC: | 220 case SEC_OID_DES_EDE3_CBC: |
237 » c = SMIME_DES_EDE3_168; | 221 c = SMIME_DES_EDE3_168; |
238 » break; | 222 break; |
239 case SEC_OID_AES_128_CBC: | 223 case SEC_OID_AES_128_CBC: |
240 » c = SMIME_AES_CBC_128; | 224 c = SMIME_AES_CBC_128; |
241 » break; | 225 break; |
242 case SEC_OID_AES_256_CBC: | 226 case SEC_OID_AES_256_CBC: |
243 » c = SMIME_AES_CBC_256; | 227 c = SMIME_AES_CBC_256; |
244 » break; | 228 break; |
245 default: | 229 default: |
246 » PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | 230 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
247 » return SECFailure; | 231 return SECFailure; |
248 } | 232 } |
249 *cipher = c; | 233 *cipher = c; |
250 return SECSuccess; | 234 return SECSuccess; |
251 } | 235 } |
252 | 236 |
253 static PRBool | 237 static PRBool nss_smime_cipher_allowed(unsigned long which) { |
254 nss_smime_cipher_allowed(unsigned long which) | 238 int mapi; |
255 { | 239 |
256 int mapi; | 240 mapi = smime_mapi_by_cipher(which); |
257 | 241 if (mapi < 0) return PR_FALSE; |
258 mapi = smime_mapi_by_cipher(which); | 242 return smime_cipher_map[mapi].allowed; |
259 if (mapi < 0) | 243 } |
260 » return PR_FALSE; | 244 |
261 return smime_cipher_map[mapi].allowed; | 245 PRBool NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key) { |
262 } | 246 unsigned long which; |
263 | 247 |
264 PRBool | 248 if (nss_smime_get_cipher_for_alg_and_key(algid, key, &which) != SECSuccess) |
265 NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key) | 249 return PR_FALSE; |
266 { | 250 |
267 unsigned long which; | 251 return nss_smime_cipher_allowed(which); |
268 | 252 } |
269 if (nss_smime_get_cipher_for_alg_and_key(algid, key, &which) != SECSuccess) | |
270 » return PR_FALSE; | |
271 | |
272 return nss_smime_cipher_allowed(which); | |
273 } | |
274 | |
275 | 253 |
276 /* | 254 /* |
277 * NSS_SMIME_EncryptionPossible - check if any encryption is allowed | 255 * NSS_SMIME_EncryptionPossible - check if any encryption is allowed |
278 * | 256 * |
279 * This tells whether or not *any* S/MIME encryption can be done, | 257 * This tells whether or not *any* S/MIME encryption can be done, |
280 * according to policy. Callers may use this to do nicer user interface | 258 * according to policy. Callers may use this to do nicer user interface |
281 * (say, greying out a checkbox so a user does not even try to encrypt | 259 * (say, greying out a checkbox so a user does not even try to encrypt |
282 * a message when they are not allowed to) or for any reason they want | 260 * a message when they are not allowed to) or for any reason they want |
283 * to check whether S/MIME encryption (or decryption, for that matter) | 261 * to check whether S/MIME encryption (or decryption, for that matter) |
284 * may be done. | 262 * may be done. |
285 * | 263 * |
286 * It takes no arguments. The return value is a simple boolean: | 264 * It takes no arguments. The return value is a simple boolean: |
287 * PR_TRUE means encryption (or decryption) is *possible* | 265 * PR_TRUE means encryption (or decryption) is *possible* |
288 * (but may still fail due to other reasons, like because we cannot | 266 * (but may still fail due to other reasons, like because we cannot |
289 * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee) | 267 * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee) |
290 * PR_FALSE means encryption (or decryption) is not permitted | 268 * PR_FALSE means encryption (or decryption) is not permitted |
291 * | 269 * |
292 * There are no errors from this routine. | 270 * There are no errors from this routine. |
293 */ | 271 */ |
294 PRBool | 272 PRBool NSS_SMIMEUtil_EncryptionPossible(void) { |
295 NSS_SMIMEUtil_EncryptionPossible(void) | 273 int i; |
296 { | 274 |
297 int i; | 275 for (i = 0; i < smime_cipher_map_count; i++) { |
298 | 276 if (smime_cipher_map[i].allowed) return PR_TRUE; |
299 for (i = 0; i < smime_cipher_map_count; i++) { | 277 } |
300 » if (smime_cipher_map[i].allowed) | 278 return PR_FALSE; |
301 » return PR_TRUE; | 279 } |
| 280 |
| 281 static int nss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap) { |
| 282 int i; |
| 283 SECOidTag capIDTag; |
| 284 |
| 285 /* we need the OIDTag here */ |
| 286 capIDTag = SECOID_FindOIDTag(&(cap->capabilityID)); |
| 287 |
| 288 /* go over all the SMIME ciphers we know and see if we find a match */ |
| 289 for (i = 0; i < smime_cipher_map_count; i++) { |
| 290 if (smime_cipher_map[i].algtag != capIDTag) continue; |
| 291 /* |
| 292 * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing |
| 293 * 2 NULLs as equal and NULL and non-NULL as not equal), we could |
| 294 * use that here instead of all of the following comparison code. |
| 295 */ |
| 296 if (!smime_cipher_map[i].parms) { |
| 297 if (!cap->parameters.data || !cap->parameters.len) |
| 298 break; /* both empty: bingo */ |
| 299 if (cap->parameters.len == 2 && |
| 300 cap->parameters.data[0] == SEC_ASN1_NULL && |
| 301 cap->parameters.data[1] == 0) |
| 302 break; /* DER NULL == NULL, bingo */ |
| 303 } else if (cap->parameters.data != NULL && |
| 304 cap->parameters.len == smime_cipher_map[i].parms->len && |
| 305 PORT_Memcmp(cap->parameters.data, |
| 306 smime_cipher_map[i].parms->data, |
| 307 cap->parameters.len) == 0) { |
| 308 break; /* both not empty, same length & equal content: bingo */ |
302 } | 309 } |
303 return PR_FALSE; | 310 } |
304 } | 311 |
305 | 312 if (i == smime_cipher_map_count) return 0; /* no match found */ |
306 | 313 return smime_cipher_map[i].cipher; /* match found, point to cipher */ |
307 static int | |
308 nss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap) | |
309 { | |
310 int i; | |
311 SECOidTag capIDTag; | |
312 | |
313 /* we need the OIDTag here */ | |
314 capIDTag = SECOID_FindOIDTag(&(cap->capabilityID)); | |
315 | |
316 /* go over all the SMIME ciphers we know and see if we find a match */ | |
317 for (i = 0; i < smime_cipher_map_count; i++) { | |
318 » if (smime_cipher_map[i].algtag != capIDTag) | |
319 » continue; | |
320 » /* | |
321 » * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing | |
322 » * 2 NULLs as equal and NULL and non-NULL as not equal), we could | |
323 » * use that here instead of all of the following comparison code. | |
324 » */ | |
325 » if (!smime_cipher_map[i].parms) {· | |
326 » if (!cap->parameters.data || !cap->parameters.len) | |
327 » » break;» /* both empty: bingo */ | |
328 » if (cap->parameters.len == 2 && | |
329 » cap->parameters.data[0] == SEC_ASN1_NULL && | |
330 » » cap->parameters.data[1] == 0)· | |
331 » » break; /* DER NULL == NULL, bingo */ | |
332 » } else if (cap->parameters.data != NULL &&· | |
333 » cap->parameters.len == smime_cipher_map[i].parms->len && | |
334 » PORT_Memcmp (cap->parameters.data, smime_cipher_map[i].parms->data, | |
335 » » » cap->parameters.len) == 0) | |
336 » { | |
337 » break;» /* both not empty, same length & equal content: bingo */ | |
338 » } | |
339 } | |
340 | |
341 if (i == smime_cipher_map_count) | |
342 » return 0;» » » » /* no match found */ | |
343 return smime_cipher_map[i].cipher;» /* match found, point to cipher */ | |
344 } | 314 } |
345 | 315 |
346 /* | 316 /* |
347 * smime_choose_cipher - choose a cipher that works for all the recipients | 317 * smime_choose_cipher - choose a cipher that works for all the recipients |
348 * | 318 * |
349 * "scert" - sender's certificate | 319 * "scert" - sender's certificate |
350 * "rcerts" - recipient's certificates | 320 * "rcerts" - recipient's certificates |
351 */ | 321 */ |
352 static long | 322 static long smime_choose_cipher(CERTCertificate *scert, |
353 smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts) | 323 CERTCertificate **rcerts) { |
354 { | 324 PLArenaPool *poolp; |
355 PLArenaPool *poolp; | 325 long cipher; |
356 long cipher; | 326 long chosen_cipher; |
357 long chosen_cipher; | 327 int *cipher_abilities; |
358 int *cipher_abilities; | 328 int *cipher_votes; |
359 int *cipher_votes; | 329 int weak_mapi; |
360 int weak_mapi; | 330 int strong_mapi; |
361 int strong_mapi; | 331 int aes128_mapi; |
362 int aes128_mapi; | 332 int aes256_mapi; |
363 int aes256_mapi; | 333 int rcount, mapi, max, i; |
364 int rcount, mapi, max, i; | 334 |
365 | 335 chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */ |
366 chosen_cipher = SMIME_RC2_CBC_40;» » /* the default, LCD */ | 336 weak_mapi = smime_mapi_by_cipher(chosen_cipher); |
367 weak_mapi = smime_mapi_by_cipher(chosen_cipher); | 337 aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128); |
368 aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128); | 338 aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256); |
369 aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256); | 339 |
370 | 340 poolp = PORT_NewArena(1024); /* XXX what is right value? */ |
371 poolp = PORT_NewArena (1024);» » /* XXX what is right value? */ | 341 if (poolp == NULL) goto done; |
372 if (poolp == NULL) | 342 |
373 » goto done; | 343 cipher_abilities = |
374 | 344 (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int)); |
375 cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * s
izeof(int)); | 345 cipher_votes = |
376 cipher_votes = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * s
izeof(int)); | 346 (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int)); |
377 if (cipher_votes == NULL || cipher_abilities == NULL) | 347 if (cipher_votes == NULL || cipher_abilities == NULL) goto done; |
378 » goto done; | 348 |
379 | 349 /* Make triple-DES the strong cipher. */ |
380 /* Make triple-DES the strong cipher. */ | 350 strong_mapi = smime_mapi_by_cipher(SMIME_DES_EDE3_168); |
381 strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168); | 351 |
382 | 352 /* walk all the recipient's certs */ |
383 /* walk all the recipient's certs */ | 353 for (rcount = 0; rcerts[rcount] != NULL; rcount++) { |
384 for (rcount = 0; rcerts[rcount] != NULL; rcount++) { | 354 SECItem *profile; |
385 » SECItem *profile; | 355 NSSSMIMECapability **caps; |
386 » NSSSMIMECapability **caps; | 356 int pref; |
387 » int pref; | 357 |
388 | 358 /* the first cipher that matches in the user's SMIME profile gets |
389 » /* the first cipher that matches in the user's SMIME profile gets | 359 * "smime_cipher_map_count" votes; the next one gets |
390 » * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_c
ount" - 1 | 360 * "smime_cipher_map_count" - 1 |
391 » * and so on. If every cipher matches, the last one gets 1 (one) vote */ | 361 * and so on. If every cipher matches, the last one gets 1 (one) vote */ |
392 » pref = smime_cipher_map_count; | 362 pref = smime_cipher_map_count; |
393 | 363 |
394 » /* find recipient's SMIME profile */ | 364 /* find recipient's SMIME profile */ |
395 » profile = CERT_FindSMimeProfile(rcerts[rcount]); | 365 profile = CERT_FindSMimeProfile(rcerts[rcount]); |
396 | 366 |
397 » if (profile != NULL && profile->data != NULL && profile->len > 0) { | 367 if (profile != NULL && profile->data != NULL && profile->len > 0) { |
398 » /* we have a profile (still DER-encoded) */ | 368 /* we have a profile (still DER-encoded) */ |
399 » caps = NULL; | 369 caps = NULL; |
400 » /* decode it */ | 370 /* decode it */ |
401 » if (SEC_QuickDERDecodeItem(poolp, &caps, | 371 if (SEC_QuickDERDecodeItem(poolp, &caps, NSSSMIMECapabilitiesTemplate, |
402 NSSSMIMECapabilitiesTemplate, profile) == SECSuccess && | 372 profile) == SECSuccess && |
403 » » caps != NULL) | 373 caps != NULL) { |
404 » { | 374 /* walk the SMIME capabilities for this recipient */ |
405 » » /* walk the SMIME capabilities for this recipient */ | 375 for (i = 0; caps[i] != NULL; i++) { |
406 » » for (i = 0; caps[i] != NULL; i++) { | 376 cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]); |
407 » » cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]); | 377 mapi = smime_mapi_by_cipher(cipher); |
408 » » mapi = smime_mapi_by_cipher(cipher); | 378 if (mapi >= 0) { |
409 » » if (mapi >= 0) { | 379 /* found the cipher */ |
410 » » » /* found the cipher */ | 380 cipher_abilities[mapi]++; |
411 » » » cipher_abilities[mapi]++; | 381 cipher_votes[mapi] += pref; |
412 » » » cipher_votes[mapi] += pref; | 382 --pref; |
413 » » » --pref; | 383 } |
414 » » } | 384 } |
415 » » } | 385 } |
416 » } | 386 } else { |
417 » } else { | 387 /* no profile found - so we can only assume that the user can do |
418 » /* no profile found - so we can only assume that the user can do | 388 * the mandatory algorithms which are RC2-40 (weak crypto) and |
419 » * the mandatory algorithms which are RC2-40 (weak crypto) and | 389 * 3DES (strong crypto), unless the user has an elliptic curve |
420 » * 3DES (strong crypto), unless the user has an elliptic curve | 390 * key. For elliptic curve keys, RFC 5753 mandates support |
421 » * key. For elliptic curve keys, RFC 5753 mandates support | 391 * for AES 128 CBC. */ |
422 » * for AES 128 CBC. */ | 392 SECKEYPublicKey *key; |
423 » SECKEYPublicKey *key; | 393 unsigned int pklen_bits; |
424 » unsigned int pklen_bits; | 394 KeyType key_type; |
425 » KeyType key_type; | 395 |
426 | 396 /* |
427 » /* | 397 * if recipient's public key length is > 512, vote for a strong cipher |
428 » * if recipient's public key length is > 512, vote for a strong ciph
er | 398 * please not that the side effect of this is that if only one recipient |
429 » * please not that the side effect of this is that if only one recip
ient | 399 * has an export-level public key, the strong cipher is disabled. |
430 » * has an export-level public key, the strong cipher is disabled. | 400 * |
431 » * | 401 * XXX This is probably only good for RSA keys. What I would |
432 » * XXX This is probably only good for RSA keys. What I would | 402 * really like is a function to just say; Is the public key in |
433 » * really like is a function to just say; Is the public key in | 403 * this cert an export-length key? Then I would not have to |
434 » * this cert an export-length key? Then I would not have to | 404 * know things like the value 512, or the kind of key, or what |
435 » * know things like the value 512, or the kind of key, or what | 405 * a subjectPublicKeyInfo is, etc. |
436 » * a subjectPublicKeyInfo is, etc. | 406 */ |
437 » */ | 407 key = CERT_ExtractPublicKey(rcerts[rcount]); |
438 » key = CERT_ExtractPublicKey(rcerts[rcount]); | 408 pklen_bits = 0; |
439 » pklen_bits = 0; | 409 if (key != NULL) { |
440 » if (key != NULL) { | 410 pklen_bits = SECKEY_PublicKeyStrengthInBits(key); |
441 » » pklen_bits = SECKEY_PublicKeyStrengthInBits (key); | 411 key_type = SECKEY_GetPublicKeyType(key); |
442 » » key_type = SECKEY_GetPublicKeyType(key); | 412 SECKEY_DestroyPublicKey(key); |
443 » » SECKEY_DestroyPublicKey (key); | 413 } |
444 » } | 414 |
445 | 415 if (key_type == ecKey) { |
446 » if (key_type == ecKey) { | 416 /* While RFC 5753 mandates support for AES-128 CBC, should use |
447 » » /* While RFC 5753 mandates support for AES-128 CBC, should use | 417 * AES 256 if user's key provides more than 128 bits of |
448 » » * AES 256 if user's key provides more than 128 bits of | 418 * security strength so that symmetric key is not weak link. */ |
449 » » * security strength so that symmetric key is not weak link. */ | 419 |
450 | 420 /* RC2-40 is not compatible with elliptic curve keys. */ |
451 » » /* RC2-40 is not compatible with elliptic curve keys. */ | 421 chosen_cipher = SMIME_DES_EDE3_168; |
452 » » chosen_cipher = SMIME_DES_EDE3_168; | 422 if (pklen_bits > 256) { |
453 » » if (pklen_bits > 256) { | 423 cipher_abilities[aes256_mapi]++; |
454 » » cipher_abilities[aes256_mapi]++; | 424 cipher_votes[aes256_mapi] += pref; |
455 » » cipher_votes[aes256_mapi] += pref; | 425 pref--; |
456 » » pref--; | 426 } |
457 » » } | 427 cipher_abilities[aes128_mapi]++; |
458 » » cipher_abilities[aes128_mapi]++; | 428 cipher_votes[aes128_mapi] += pref; |
459 » » cipher_votes[aes128_mapi] += pref; | 429 pref--; |
460 » » pref--; | 430 cipher_abilities[strong_mapi]++; |
461 » » cipher_abilities[strong_mapi]++; | 431 cipher_votes[strong_mapi] += pref; |
462 » » cipher_votes[strong_mapi] += pref; | 432 pref--; |
463 » » pref--; | 433 } else { |
464 » } else { | 434 if (pklen_bits > 512) { |
465 » » if (pklen_bits > 512) { | 435 /* cast votes for the strong algorithm */ |
466 » » /* cast votes for the strong algorithm */ | 436 cipher_abilities[strong_mapi]++; |
467 » » cipher_abilities[strong_mapi]++; | 437 cipher_votes[strong_mapi] += pref; |
468 » » cipher_votes[strong_mapi] += pref; | 438 pref--; |
469 » » pref--; | 439 } |
470 » » } | 440 |
471 | 441 /* always cast (possibly less) votes for the weak algorithm */ |
472 » » /* always cast (possibly less) votes for the weak algorithm */ | 442 cipher_abilities[weak_mapi]++; |
473 » » cipher_abilities[weak_mapi]++; | 443 cipher_votes[weak_mapi] += pref; |
474 » » cipher_votes[weak_mapi] += pref; | 444 } |
475 » }· | |
476 » } | |
477 » if (profile != NULL) | |
478 » SECITEM_FreeItem(profile, PR_TRUE); | |
479 } | 445 } |
480 | 446 if (profile != NULL) SECITEM_FreeItem(profile, PR_TRUE); |
481 /* find cipher that is agreeable by all recipients and that has the most vot
es */ | 447 } |
482 max = 0; | 448 |
483 for (mapi = 0; mapi < smime_cipher_map_count; mapi++) { | 449 /* find cipher that is agreeable by all recipients and that has the most votes |
484 » /* if not all of the recipients can do this, forget it */ | 450 */ |
485 » if (cipher_abilities[mapi] != rcount) | 451 max = 0; |
486 » continue; | 452 for (mapi = 0; mapi < smime_cipher_map_count; mapi++) { |
487 » /* if cipher is not enabled or not allowed by policy, forget it */ | 453 /* if not all of the recipients can do this, forget it */ |
488 » if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed) | 454 if (cipher_abilities[mapi] != rcount) continue; |
489 » continue; | 455 /* if cipher is not enabled or not allowed by policy, forget it */ |
490 » /* now see if this one has more votes than the last best one */ | 456 if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed) |
491 » if (cipher_votes[mapi] >= max) { | 457 continue; |
492 » /* if equal number of votes, prefer the ones further down in the lis
t */ | 458 /* now see if this one has more votes than the last best one */ |
493 » /* with the expectation that these are higher rated ciphers */ | 459 if (cipher_votes[mapi] >= max) { |
494 » chosen_cipher = smime_cipher_map[mapi].cipher; | 460 /* if equal number of votes, prefer the ones further down in the list */ |
495 » max = cipher_votes[mapi]; | 461 /* with the expectation that these are higher rated ciphers */ |
496 » } | 462 chosen_cipher = smime_cipher_map[mapi].cipher; |
| 463 max = cipher_votes[mapi]; |
497 } | 464 } |
498 /* if no common cipher was found, chosen_cipher stays at the default */ | 465 } |
| 466 /* if no common cipher was found, chosen_cipher stays at the default */ |
499 | 467 |
500 done: | 468 done: |
501 if (poolp != NULL) | 469 if (poolp != NULL) PORT_FreeArena(poolp, PR_FALSE); |
502 » PORT_FreeArena (poolp, PR_FALSE); | 470 |
503 | 471 return chosen_cipher; |
504 return chosen_cipher; | |
505 } | 472 } |
506 | 473 |
507 /* | 474 /* |
508 * XXX This is a hack for now to satisfy our current interface. | 475 * XXX This is a hack for now to satisfy our current interface. |
509 * Eventually, with more parameters needing to be specified, just | 476 * Eventually, with more parameters needing to be specified, just |
510 * looking up the keysize is not going to be sufficient. | 477 * looking up the keysize is not going to be sufficient. |
511 */ | 478 */ |
512 static int | 479 static int smime_keysize_by_cipher(unsigned long which) { |
513 smime_keysize_by_cipher (unsigned long which) | 480 int keysize; |
514 { | 481 |
515 int keysize; | 482 switch (which) { |
516 | 483 case SMIME_RC2_CBC_40: |
517 switch (which) { | 484 keysize = 40; |
518 case SMIME_RC2_CBC_40: | 485 break; |
519 » keysize = 40; | 486 case SMIME_RC2_CBC_64: |
520 » break; | 487 keysize = 64; |
521 case SMIME_RC2_CBC_64: | 488 break; |
522 » keysize = 64; | 489 case SMIME_RC2_CBC_128: |
523 » break; | 490 case SMIME_AES_CBC_128: |
524 case SMIME_RC2_CBC_128: | 491 keysize = 128; |
525 case SMIME_AES_CBC_128: | 492 break; |
526 » keysize = 128; | 493 case SMIME_AES_CBC_256: |
527 » break; | 494 keysize = 256; |
528 case SMIME_AES_CBC_256: | 495 break; |
529 » keysize = 256; | 496 case SMIME_DES_CBC_56: |
530 » break; | 497 case SMIME_DES_EDE3_168: |
531 case SMIME_DES_CBC_56: | 498 /* |
532 case SMIME_DES_EDE3_168: | 499 * These are special; since the key size is fixed, we actually |
533 » /* | 500 * want to *avoid* specifying a key size. |
534 » * These are special; since the key size is fixed, we actually | 501 */ |
535 » * want to *avoid* specifying a key size. | 502 keysize = 0; |
536 » */ | 503 break; |
537 » keysize = 0; | 504 default: |
538 » break; | 505 keysize = -1; |
539 default: | 506 break; |
540 » keysize = -1; | 507 } |
541 » break; | 508 |
542 } | 509 return keysize; |
543 | 510 } |
544 return keysize; | 511 |
545 } | 512 /* |
546 | 513 * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all |
547 /* | 514 *recipients |
548 * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all
recipients | 515 * |
549 * | 516 * it would be great for UI purposes if there would be a way to find out which |
550 * it would be great for UI purposes if there would be a way to find out which r
ecipients | 517 *recipients |
551 * prevented a strong cipher from being used... | 518 * prevented a strong cipher from being used... |
552 */ | 519 */ |
553 SECStatus | 520 SECStatus NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, |
554 NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, SECOidTag *bulk
algtag, int *keysize) | 521 SECOidTag *bulkalgtag, |
555 { | 522 int *keysize) { |
556 unsigned long cipher; | 523 unsigned long cipher; |
557 int mapi; | 524 int mapi; |
558 | 525 |
559 cipher = smime_choose_cipher(NULL, rcerts); | 526 cipher = smime_choose_cipher(NULL, rcerts); |
560 mapi = smime_mapi_by_cipher(cipher); | 527 mapi = smime_mapi_by_cipher(cipher); |
561 | 528 |
562 *bulkalgtag = smime_cipher_map[mapi].algtag; | 529 *bulkalgtag = smime_cipher_map[mapi].algtag; |
563 *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher); | 530 *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher); |
564 | 531 |
565 return SECSuccess; | 532 return SECSuccess; |
566 } | 533 } |
567 | 534 |
568 /* | 535 /* |
569 * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities for this inst
ance of NSS | 536 * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities for this |
| 537 *instance of NSS |
570 * | 538 * |
571 * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant | 539 * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant |
572 * S/MIME capabilities attribute value. | 540 * S/MIME capabilities attribute value. |
573 * | 541 * |
574 * XXX Please note that, in contradiction to RFC2633 2.5.2, the capabilities onl
y include | 542 * XXX Please note that, in contradiction to RFC2633 2.5.2, the capabilities |
| 543 *only include |
575 * symmetric ciphers, NO signature algorithms or key encipherment algorithms. | 544 * symmetric ciphers, NO signature algorithms or key encipherment algorithms. |
576 * | 545 * |
577 * "poolp" - arena pool to create the S/MIME capabilities data on | 546 * "poolp" - arena pool to create the S/MIME capabilities data on |
578 * "dest" - SECItem to put the data in | 547 * "dest" - SECItem to put the data in |
579 */ | 548 */ |
580 SECStatus | 549 SECStatus NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, |
581 NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, SECItem *dest) | 550 SECItem *dest) { |
582 { | 551 NSSSMIMECapability *cap; |
583 NSSSMIMECapability *cap; | 552 NSSSMIMECapability **smime_capabilities; |
584 NSSSMIMECapability **smime_capabilities; | 553 smime_cipher_map_entry *map; |
585 smime_cipher_map_entry *map; | 554 SECOidData *oiddata; |
586 SECOidData *oiddata; | 555 SECItem *dummy; |
587 SECItem *dummy; | 556 int i, capIndex; |
588 int i, capIndex; | 557 |
589 | 558 /* if we have an old NSSSMIMECapability array, we'll reuse it (has the right |
590 /* if we have an old NSSSMIMECapability array, we'll reuse it (has the right
size) */ | 559 * size) */ |
591 /* smime_cipher_map_count + 1 is an upper bound - we might end up with less
*/ | 560 /* smime_cipher_map_count + 1 is an upper bound - we might end up with less */ |
592 smime_capabilities = (NSSSMIMECapability **)PORT_ZAlloc((smime_cipher_map_co
unt + 1) | 561 smime_capabilities = (NSSSMIMECapability **)PORT_ZAlloc( |
593 » » » » * sizeof(NSSSMIMECapability *)); | 562 (smime_cipher_map_count + 1) * sizeof(NSSSMIMECapability *)); |
594 if (smime_capabilities == NULL) | 563 if (smime_capabilities == NULL) return SECFailure; |
595 » return SECFailure; | 564 |
596 | 565 capIndex = 0; |
597 capIndex = 0; | 566 |
598 | 567 /* Add all the symmetric ciphers |
599 /* Add all the symmetric ciphers | 568 * We walk the cipher list backwards, as it is ordered by increasing strength, |
600 * We walk the cipher list backwards, as it is ordered by increasing strengt
h, | 569 * we prefer the stronger cipher over a weaker one, and we have to list the |
601 * we prefer the stronger cipher over a weaker one, and we have to list the | 570 * preferred algorithm first */ |
602 * preferred algorithm first */ | 571 for (i = smime_cipher_map_count - 1; i >= 0; i--) { |
603 for (i = smime_cipher_map_count - 1; i >= 0; i--) { | 572 /* Find the corresponding entry in the cipher map. */ |
604 » /* Find the corresponding entry in the cipher map. */ | 573 map = &(smime_cipher_map[i]); |
605 » map = &(smime_cipher_map[i]); | 574 if (!map->enabled) continue; |
606 » if (!map->enabled) | 575 |
607 » continue; | 576 /* get next SMIME capability */ |
608 | 577 cap = (NSSSMIMECapability *)PORT_ZAlloc(sizeof(NSSSMIMECapability)); |
609 » /* get next SMIME capability */ | 578 if (cap == NULL) break; |
610 » cap = (NSSSMIMECapability *)PORT_ZAlloc(sizeof(NSSSMIMECapability)); | 579 smime_capabilities[capIndex++] = cap; |
611 » if (cap == NULL) | 580 |
612 » break; | 581 oiddata = SECOID_FindOIDByTag(map->algtag); |
613 » smime_capabilities[capIndex++] = cap; | 582 if (oiddata == NULL) break; |
614 | 583 |
615 » oiddata = SECOID_FindOIDByTag(map->algtag); | 584 cap->capabilityID.data = oiddata->oid.data; |
616 » if (oiddata == NULL) | 585 cap->capabilityID.len = oiddata->oid.len; |
617 » break; | 586 cap->parameters.data = map->parms ? map->parms->data : NULL; |
618 | 587 cap->parameters.len = map->parms ? map->parms->len : 0; |
619 » cap->capabilityID.data = oiddata->oid.data; | 588 cap->cipher = smime_cipher_map[i].cipher; |
620 » cap->capabilityID.len = oiddata->oid.len; | 589 } |
621 » cap->parameters.data = map->parms ? map->parms->data : NULL; | 590 |
622 » cap->parameters.len = map->parms ? map->parms->len : 0; | 591 /* XXX add signature algorithms */ |
623 » cap->cipher = smime_cipher_map[i].cipher; | 592 /* XXX add key encipherment algorithms */ |
624 } | 593 |
625 | 594 smime_capabilities[capIndex] = NULL; /* last one - now encode */ |
626 /* XXX add signature algorithms */ | 595 dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, |
627 /* XXX add key encipherment algorithms */ | 596 NSSSMIMECapabilitiesTemplate); |
628 | 597 |
629 smime_capabilities[capIndex] = NULL;» /* last one - now encode */ | 598 /* now that we have the proper encoded SMIMECapabilities (or not), |
630 dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, NSSSMIMECapabil
itiesTemplate); | 599 * free the work data */ |
631 | 600 for (i = 0; smime_capabilities[i] != NULL; i++) |
632 /* now that we have the proper encoded SMIMECapabilities (or not), | 601 PORT_Free(smime_capabilities[i]); |
633 * free the work data */ | 602 PORT_Free(smime_capabilities); |
634 for (i = 0; smime_capabilities[i] != NULL; i++) | 603 |
635 » PORT_Free(smime_capabilities[i]); | 604 return (dummy == NULL) ? SECFailure : SECSuccess; |
636 PORT_Free(smime_capabilities); | 605 } |
637 | 606 |
638 return (dummy == NULL) ? SECFailure : SECSuccess; | 607 /* |
639 } | 608 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key |
640 | 609 *preferences attr value |
641 /* | |
642 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferenc
es attr value | |
643 * | 610 * |
644 * "poolp" - arena pool to create the attr value on | 611 * "poolp" - arena pool to create the attr value on |
645 * "dest" - SECItem to put the data in | 612 * "dest" - SECItem to put the data in |
646 * "cert" - certificate that should be marked as preferred encryption key | 613 * "cert" - certificate that should be marked as preferred encryption key |
647 * cert is expected to have been verified for EmailRecipient usage. | 614 * cert is expected to have been verified for EmailRecipient usage. |
648 */ | 615 */ |
649 SECStatus | 616 SECStatus NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, |
650 NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCert
ificate *cert) | 617 SECItem *dest, |
651 { | 618 CERTCertificate *cert) { |
652 NSSSMIMEEncryptionKeyPreference ekp; | 619 NSSSMIMEEncryptionKeyPreference ekp; |
653 SECItem *dummy = NULL; | 620 SECItem *dummy = NULL; |
654 PLArenaPool *tmppoolp = NULL; | 621 PLArenaPool *tmppoolp = NULL; |
655 | 622 |
656 if (cert == NULL) | 623 if (cert == NULL) goto loser; |
657 » goto loser; | 624 |
658 | 625 tmppoolp = PORT_NewArena(1024); |
659 tmppoolp = PORT_NewArena(1024); | 626 if (tmppoolp == NULL) goto loser; |
660 if (tmppoolp == NULL) | 627 |
661 » goto loser; | 628 /* XXX hardcoded IssuerSN choice for now */ |
662 | 629 ekp.selector = NSSSMIMEEncryptionKeyPref_IssuerSN; |
663 /* XXX hardcoded IssuerSN choice for now */ | 630 ekp.id.issuerAndSN = CERT_GetCertIssuerAndSN(tmppoolp, cert); |
664 ekp.selector = NSSSMIMEEncryptionKeyPref_IssuerSN; | 631 if (ekp.id.issuerAndSN == NULL) goto loser; |
665 ekp.id.issuerAndSN = CERT_GetCertIssuerAndSN(tmppoolp, cert); | 632 |
666 if (ekp.id.issuerAndSN == NULL) | 633 dummy = |
667 » goto loser; | 634 SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_template); |
668 | |
669 dummy = SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_templa
te); | |
670 | 635 |
671 loser: | 636 loser: |
672 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); | 637 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); |
673 | 638 |
674 return (dummy == NULL) ? SECFailure : SECSuccess; | 639 return (dummy == NULL) ? SECFailure : SECSuccess; |
675 } | 640 } |
676 | 641 |
677 /* | 642 /* |
678 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferenc
es attr value using MS oid | 643 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key |
| 644 *preferences attr value using MS oid |
679 * | 645 * |
680 * "poolp" - arena pool to create the attr value on | 646 * "poolp" - arena pool to create the attr value on |
681 * "dest" - SECItem to put the data in | 647 * "dest" - SECItem to put the data in |
682 * "cert" - certificate that should be marked as preferred encryption key | 648 * "cert" - certificate that should be marked as preferred encryption key |
683 * cert is expected to have been verified for EmailRecipient usage. | 649 * cert is expected to have been verified for EmailRecipient usage. |
684 */ | 650 */ |
685 SECStatus | 651 SECStatus NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, |
686 NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCe
rtificate *cert) | 652 SECItem *dest, |
687 { | 653 CERTCertificate *cert) { |
688 SECItem *dummy = NULL; | 654 SECItem *dummy = NULL; |
689 PLArenaPool *tmppoolp = NULL; | 655 PLArenaPool *tmppoolp = NULL; |
690 CERTIssuerAndSN *isn; | 656 CERTIssuerAndSN *isn; |
691 | 657 |
692 if (cert == NULL) | 658 if (cert == NULL) goto loser; |
693 » goto loser; | 659 |
694 | 660 tmppoolp = PORT_NewArena(1024); |
695 tmppoolp = PORT_NewArena(1024); | 661 if (tmppoolp == NULL) goto loser; |
696 if (tmppoolp == NULL) | 662 |
697 » goto loser; | 663 isn = CERT_GetCertIssuerAndSN(tmppoolp, cert); |
698 | 664 if (isn == NULL) goto loser; |
699 isn = CERT_GetCertIssuerAndSN(tmppoolp, cert); | 665 |
700 if (isn == NULL) | 666 dummy = SEC_ASN1EncodeItem(poolp, dest, isn, |
701 » goto loser; | 667 SEC_ASN1_GET(CERT_IssuerAndSNTemplate)); |
702 | |
703 dummy = SEC_ASN1EncodeItem(poolp, dest, isn, SEC_ASN1_GET(CERT_IssuerAndSNTe
mplate)); | |
704 | 668 |
705 loser: | 669 loser: |
706 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); | 670 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); |
707 | 671 |
708 return (dummy == NULL) ? SECFailure : SECSuccess; | 672 return (dummy == NULL) ? SECFailure : SECSuccess; |
709 } | 673 } |
710 | 674 |
711 /* | 675 /* |
712 * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference - | 676 * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference - |
713 *» » » » find cert marked by EncryptionKeyPreference attr
ibute | 677 *» » » » find cert marked by EncryptionKeyPreference |
| 678 *attribute |
714 * | 679 * |
715 * "certdb" - handle for the cert database to look in | 680 * "certdb" - handle for the cert database to look in |
716 * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute | 681 * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute |
717 * | 682 * |
718 * if certificate is supposed to be found among the message's included certifica
tes, | 683 * if certificate is supposed to be found among the message's included |
| 684 *certificates, |
719 * they are assumed to have been imported already. | 685 * they are assumed to have been imported already. |
720 */ | 686 */ |
721 CERTCertificate * | 687 CERTCertificate *NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference( |
722 NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECIt
em *DERekp) | 688 CERTCertDBHandle *certdb, SECItem *DERekp) { |
723 { | 689 PLArenaPool *tmppoolp = NULL; |
724 PLArenaPool *tmppoolp = NULL; | 690 CERTCertificate *cert = NULL; |
725 CERTCertificate *cert = NULL; | 691 NSSSMIMEEncryptionKeyPreference ekp; |
726 NSSSMIMEEncryptionKeyPreference ekp; | 692 |
727 | 693 tmppoolp = PORT_NewArena(1024); |
728 tmppoolp = PORT_NewArena(1024); | 694 if (tmppoolp == NULL) return NULL; |
729 if (tmppoolp == NULL) | 695 |
730 » return NULL; | 696 /* decode DERekp */ |
731 | 697 if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, |
732 /* decode DERekp */ | 698 DERekp) != SECSuccess) |
733 if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, | 699 goto loser; |
734 DERekp) != SECSuccess) | 700 |
735 » goto loser; | 701 /* find cert */ |
736 | 702 switch (ekp.selector) { |
737 /* find cert */ | |
738 switch (ekp.selector) { | |
739 case NSSSMIMEEncryptionKeyPref_IssuerSN: | 703 case NSSSMIMEEncryptionKeyPref_IssuerSN: |
740 » cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN); | 704 cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN); |
741 » break; | 705 break; |
742 case NSSSMIMEEncryptionKeyPref_RKeyID: | 706 case NSSSMIMEEncryptionKeyPref_RKeyID: |
743 case NSSSMIMEEncryptionKeyPref_SubjectKeyID: | 707 case NSSSMIMEEncryptionKeyPref_SubjectKeyID: |
744 » /* XXX not supported yet - we need to be able to look up certs by Subjec
tKeyID */ | 708 /* XXX not supported yet - we need to be able to look up certs by |
745 » break; | 709 * SubjectKeyID */ |
| 710 break; |
746 default: | 711 default: |
747 » PORT_Assert(0); | 712 PORT_Assert(0); |
748 } | 713 } |
749 loser: | 714 loser: |
750 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); | 715 if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); |
751 | 716 |
752 return cert; | 717 return cert; |
753 } | 718 } |
754 | 719 |
755 extern const char __nss_smime_rcsid[]; | 720 extern const char __nss_smime_rcsid[]; |
756 extern const char __nss_smime_sccsid[]; | 721 extern const char __nss_smime_sccsid[]; |
757 | 722 |
758 PRBool | 723 PRBool NSSSMIME_VersionCheck(const char *importedVersion) { |
759 NSSSMIME_VersionCheck(const char *importedVersion) | 724 /* |
760 { | 725 * This is the secret handshake algorithm. |
761 /* | 726 * |
762 * This is the secret handshake algorithm. | 727 * This release has a simple version compatibility |
763 * | 728 * check algorithm. This release is not backward |
764 * This release has a simple version compatibility | 729 * compatible with previous major releases. It is |
765 * check algorithm. This release is not backward | 730 * not compatible with future major, minor, or |
766 * compatible with previous major releases. It is | 731 * patch releases. |
767 * not compatible with future major, minor, or | 732 */ |
768 * patch releases. | 733 volatile char c; /* force a reference that won't get optimized away */ |
769 */ | 734 |
770 volatile char c; /* force a reference that won't get optimized away */ | 735 c = __nss_smime_rcsid[0] + __nss_smime_sccsid[0]; |
771 | 736 |
772 c = __nss_smime_rcsid[0] + __nss_smime_sccsid[0];· | 737 return NSS_VersionCheck(importedVersion); |
773 | 738 } |
774 return NSS_VersionCheck(importedVersion); | 739 |
775 } | 740 const char *NSSSMIME_GetVersion(void) { return NSS_VERSION; } |
776 | |
777 const char * | |
778 NSSSMIME_GetVersion(void) | |
779 { | |
780 return NSS_VERSION; | |
781 } | |
OLD | NEW |