security/nss/lib/smime/cmspubkey.c

changeset 2
7e26c7da4463
equal deleted inserted replaced
-1:000000000000 0:e91385ff0405
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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * CMS public key crypto
7 */
8
9 #include "cmslocal.h"
10
11 #include "cert.h"
12 #include "key.h"
13 #include "secasn1.h"
14 #include "secitem.h"
15 #include "secoid.h"
16 #include "pk11func.h"
17 #include "secerr.h"
18
19 /* ====== RSA ======================================================================= */
20
21 /*
22 * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA
23 *
24 * this function takes a symmetric key and encrypts it using an RSA public key
25 * according to PKCS#1 and RFC2633 (S/MIME)
26 */
27 SECStatus
28 NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
29 PK11SymKey *bulkkey,
30 SECItem *encKey)
31 {
32 SECStatus rv;
33 SECKEYPublicKey *publickey;
34
35 publickey = CERT_ExtractPublicKey(cert);
36 if (publickey == NULL)
37 return SECFailure;
38
39 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, publickey, bulkkey, encKey);
40 SECKEY_DestroyPublicKey(publickey);
41 return rv;
42 }
43
44 SECStatus
45 NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
46 SECKEYPublicKey *publickey,
47 PK11SymKey *bulkkey, SECItem *encKey)
48 {
49 SECStatus rv;
50 int data_len;
51 KeyType keyType;
52 void *mark = NULL;
53
54
55 mark = PORT_ArenaMark(poolp);
56 if (!mark)
57 goto loser;
58
59 /* sanity check */
60 keyType = SECKEY_GetPublicKeyType(publickey);
61 PORT_Assert(keyType == rsaKey);
62 if (keyType != rsaKey) {
63 goto loser;
64 }
65 /* allocate memory for the encrypted key */
66 data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */
67 encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
68 encKey->len = data_len;
69 if (encKey->data == NULL)
70 goto loser;
71
72 /* encrypt the key now */
73 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION),
74 publickey, bulkkey, encKey);
75
76 if (rv != SECSuccess)
77 goto loser;
78
79 PORT_ArenaUnmark(poolp, mark);
80 return SECSuccess;
81
82 loser:
83 if (mark) {
84 PORT_ArenaRelease(poolp, mark);
85 }
86 return SECFailure;
87 }
88
89 /*
90 * NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key
91 *
92 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric
93 * key handle. Please note that the actual unwrapped key data may not be allowed to leave
94 * a hardware token...
95 */
96 PK11SymKey *
97 NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag)
98 {
99 /* that's easy */
100 CK_MECHANISM_TYPE target;
101 PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
102 target = PK11_AlgtagToMechanism(bulkalgtag);
103 if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) {
104 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
105 return NULL;
106 }
107 return PK11_PubUnwrapSymKey(privkey, encKey, target, CKA_DECRYPT, 0);
108 }
109
110 /* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
111
112 SECStatus
113 NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
114 SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
115 SECItem *pubKey)
116 {
117 #if 0 /* not yet done */
118 SECOidTag certalgtag; /* the certificate's encryption algorithm */
119 SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
120 SECStatus rv;
121 SECItem *params = NULL;
122 int data_len;
123 SECStatus err;
124 PK11SymKey *tek;
125 CERTCertificate *ourCert;
126 SECKEYPublicKey *ourPubKey;
127 NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid;
128
129 certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
130 PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
131
132 /* We really want to show our KEA tag as the key exchange algorithm tag. */
133 encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
134
135 /* Get the public key of the recipient. */
136 publickey = CERT_ExtractPublicKey(cert);
137 if (publickey == NULL) goto loser;
138
139 /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
140 /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
141 if (ourCert == NULL) goto loser;
142
143 arena = PORT_NewArena(1024);
144 if (arena == NULL) goto loser;
145
146 /* While we're here, extract the key pair's public key data and copy it into */
147 /* the outgoing parameters. */
148 /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
149 if (ourPubKey == NULL)
150 {
151 goto loser;
152 }
153 SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
154 SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
155 ourPubKey = NULL;
156
157 /* Extract our private key in order to derive the KEA key. */
158 ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
159 CERT_DestroyCertificate(ourCert); /* we're done with this */
160 if (!ourPrivKey) goto loser;
161
162 /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
163 if (ukm) {
164 ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
165 ukm->len = /* XXXX */;
166 }
167
168 /* Generate the KEK (key exchange key) according to RFC2631 which we use
169 * to wrap the bulk encryption key. */
170 kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
171 ukm, NULL,
172 /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
173 CKA_WRAP, 0, wincx);
174
175 SECKEY_DestroyPublicKey(publickey);
176 SECKEY_DestroyPrivateKey(ourPrivKey);
177 publickey = NULL;
178 ourPrivKey = NULL;
179
180 if (!kek)
181 goto loser;
182
183 /* allocate space for the encrypted CEK (bulk key) */
184 encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
185 encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
186
187 if (encKey->data == NULL)
188 {
189 PK11_FreeSymKey(kek);
190 goto loser;
191 }
192
193
194 /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
195 /* bulk encryption algorithm */
196 switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
197 {
198 case /* XXXX */CKM_SKIPJACK_CFB8:
199 err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
200 whichKEA = NSSCMSKEAUsesSkipjack;
201 break;
202 case /* XXXX */CKM_SKIPJACK_CFB8:
203 err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
204 whichKEA = NSSCMSKEAUsesSkipjack;
205 break;
206 default:
207 /* XXXX what do we do here? Neither RC2 nor 3DES... */
208 err = SECFailure;
209 /* set error */
210 break;
211 }
212
213 PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
214 if (err != SECSuccess)
215 goto loser;
216
217 PORT_Assert(whichKEA != NSSCMSKEAInvalid);
218
219 /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
220 /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
221 params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
222 if (params == NULL)
223 goto loser;
224
225 /* now set keyEncAlg */
226 rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
227 if (rv != SECSuccess)
228 goto loser;
229
230 /* XXXXXXX this is not right yet */
231 loser:
232 if (arena) {
233 PORT_FreeArena(arena, PR_FALSE);
234 }
235 if (publickey) {
236 SECKEY_DestroyPublicKey(publickey);
237 }
238 if (ourPrivKey) {
239 SECKEY_DestroyPrivateKey(ourPrivKey);
240 }
241 #endif
242 return SECFailure;
243 }
244
245 PK11SymKey *
246 NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
247 {
248 #if 0 /* not yet done */
249 SECStatus err;
250 CK_MECHANISM_TYPE bulkType;
251 PK11SymKey *tek;
252 SECKEYPublicKey *originatorPubKey;
253 NSSCMSSMIMEKEAParameters keaParams;
254
255 /* XXXX get originator's public key */
256 originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
257 keaParams.originatorKEAKey.len);
258 if (originatorPubKey == NULL)
259 goto loser;
260
261 /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
262 The Derive function generates a shared secret and combines it with the originatorRA
263 data to come up with an unique session key */
264 tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
265 &keaParams.originatorRA, NULL,
266 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
267 CKA_WRAP, 0, pwfn_arg);
268 SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
269 if (tek == NULL)
270 goto loser;
271
272 /* Now that we have the TEK, unwrap the bulk key
273 with which to decrypt the message. */
274 /* Skipjack is being used as the bulk encryption algorithm.*/
275 /* Unwrap the bulk key. */
276 bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
277 encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
278
279 return bulkkey;
280
281 loser:
282 #endif
283 return NULL;
284 }
285

mercurial