Coverage Report

Created: 2018-09-25 14:53

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