]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_ec_keyx.c
Some cleanup
[openssl-gost/engine.git] / gost_ec_keyx.c
1 /**********************************************************************
2  *                        gost_ec_keyx.c                              *
3  *             Copyright (c) 2005-2013 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *   VK0 34.10-2001 key exchange and GOST R 34.10-2001                *
7  *   based PKCS7/SMIME support                                        *
8  *          Requires OpenSSL 0.9.9 for compilation                    *
9  **********************************************************************/
10 #include <openssl/evp.h>
11 #include <openssl/err.h>
12 #include <openssl/rand.h>
13 #include <string.h>
14 #include <openssl/objects.h>
15 #include "gost89.h"
16 #include "e_gost_err.h"
17 #include "gost_keywrap.h"
18 #include "gost_lcl.h"
19
20 /* Implementation of CryptoPro VKO 34.10-2001/2012 algorithm */
21 static int VKO_compute_key(unsigned char *shared_key, size_t shared_key_size,
22                            const EC_POINT *pub_key, EC_KEY *priv_key,
23                            const unsigned char *ukm, int dgst_nid)
24 {
25     unsigned char *databuf = NULL;
26     BIGNUM *UKM = NULL, *p = NULL, *order = NULL, *X = NULL, *Y = NULL;
27     const BIGNUM *key = EC_KEY_get0_private_key(priv_key);
28     EC_POINT *pnt = EC_POINT_new(EC_KEY_get0_group(priv_key));
29     int i;
30     BN_CTX *ctx = BN_CTX_new();
31     EVP_MD_CTX *mdctx = NULL;
32     const EVP_MD *md = NULL;
33     int effective_dgst_nid = (dgst_nid == NID_id_GostR3411_2012_512) ?
34         NID_id_GostR3411_2012_256 : dgst_nid;
35     int buf_len = (dgst_nid == NID_id_GostR3411_2012_512) ? 128 : 64,
36         half_len = buf_len >> 1;
37                 int ret = 0;
38
39     if (!ctx) {
40         GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
41         return 0;
42     }
43     BN_CTX_start(ctx);
44
45     databuf = OPENSSL_zalloc(buf_len);
46     if (!databuf) {
47         GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
48         goto err;
49     }
50
51     md = EVP_get_digestbynid(effective_dgst_nid);
52     if (!md) {
53         GOSTerr(GOST_F_VKO_COMPUTE_KEY, GOST_R_INVALID_DIGEST_TYPE);
54         goto err;
55     }
56
57     UKM = hashsum2bn(ukm, 8);
58     p = BN_CTX_get(ctx);
59     order = BN_CTX_get(ctx);
60     X = BN_CTX_get(ctx);
61     Y = BN_CTX_get(ctx);
62     EC_GROUP_get_order(EC_KEY_get0_group(priv_key), order, ctx);
63     BN_mod_mul(p, key, UKM, order, ctx);
64     if (!EC_POINT_mul
65         (EC_KEY_get0_group(priv_key), pnt, NULL, pub_key, p, ctx)) {
66         GOSTerr(GOST_F_VKO_COMPUTE_KEY, GOST_R_ERROR_POINT_MUL);
67         goto err;
68     }
69     EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key),
70                                         pnt, X, Y, ctx);
71     /*
72      * Serialize elliptic curve point same way as we do it when saving key
73      */
74     store_bignum(Y, databuf, half_len);
75     store_bignum(X, databuf + half_len, half_len);
76     /* And reverse byte order of whole buffer */
77                 BUF_reverse(databuf, NULL, buf_len);
78
79     mdctx = EVP_MD_CTX_new();
80     if (!mdctx) {
81         GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
82         goto err;
83     }
84     EVP_MD_CTX_init(mdctx);
85     EVP_DigestInit_ex(mdctx, md, NULL);
86     EVP_DigestUpdate(mdctx, databuf, buf_len);
87     EVP_DigestFinal_ex(mdctx, shared_key, NULL);
88                 ret = 32;
89
90  err:
91     BN_free(UKM);
92     BN_CTX_end(ctx);
93     BN_CTX_free(ctx);
94
95     EC_POINT_free(pnt);
96
97     EVP_MD_CTX_free(mdctx);
98
99     OPENSSL_free(databuf);
100
101     return ret;
102 }
103
104 /*
105  * EVP_PKEY_METHOD callback derive.
106  * Implements VKO R 34.10-2001/2012 algorithms
107  */
108 int pkey_gost_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
109 {
110     /*
111      * Public key of peer in the ctx field peerkey
112      * Our private key in the ctx pkey
113      * ukm is in the algorithm specific context data
114      */
115     EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
116     EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
117     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
118     int dgst_nid = NID_undef;
119
120     if (!data || !data->shared_ukm) {
121         GOSTerr(GOST_F_PKEY_GOST_EC_DERIVE, GOST_R_UKM_NOT_SET);
122         return 0;
123     }
124
125     if (key == NULL) {
126         *keylen = 32;
127         return 1;
128     }
129
130     EVP_PKEY_get_default_digest_nid(my_key, &dgst_nid);
131
132     *keylen =
133         VKO_compute_key(key, 32,
134                         EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)),
135                         (EC_KEY *)EVP_PKEY_get0(my_key), data->shared_ukm,
136                         dgst_nid);
137     return (*keylen) ? 1 : 0;
138 }
139
140 /*
141  * Generates ephemeral key based on pubk algorithm computes shared key using
142  * VKO and returns filled up GOST_KEY_TRANSPORT structure
143  */
144
145 /*
146  * EVP_PKEY_METHOD callback encrypt
147  * Implementation of GOST2001 key transport, cryptopo variation
148  */
149
150 int pkey_GOST_ECcp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
151                            size_t *out_len, const unsigned char *key,
152                            size_t key_len)
153 {
154     GOST_KEY_TRANSPORT *gkt = NULL;
155     EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
156     struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
157     int pkey_nid = EVP_PKEY_base_id(pubk);
158     ASN1_OBJECT *crypt_params_obj = (pkey_nid == NID_id_GostR3410_2001) ?
159         OBJ_nid2obj(NID_id_Gost28147_89_CryptoPro_A_ParamSet) :
160         OBJ_nid2obj(NID_id_tc26_gost_28147_param_Z);
161     const struct gost_cipher_info *param =
162         get_encryption_params(crypt_params_obj);
163     unsigned char ukm[8], shared_key[32], crypted_key[44];
164     int ret = 0;
165     int key_is_ephemeral = 1;
166     gost_ctx cctx;
167     EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx);
168     if (data->shared_ukm) {
169         memcpy(ukm, data->shared_ukm, 8);
170     } else if (out) {
171
172         if (RAND_bytes(ukm, 8) <= 0) {
173             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, GOST_R_RNG_ERROR);
174             return 0;
175         }
176     }
177     /* Check for private key in the peer_key of context */
178     if (sec_key) {
179         key_is_ephemeral = 0;
180         if (!gost_get0_priv_key(sec_key)) {
181             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT,
182                     GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR);
183             goto err;
184         }
185     } else {
186         key_is_ephemeral = 1;
187         if (out) {
188             sec_key = EVP_PKEY_new();
189             if (! EVP_PKEY_assign(sec_key, EVP_PKEY_base_id(pubk), EC_KEY_new()) ||
190                                   ! EVP_PKEY_copy_parameters(sec_key, pubk) ||
191                 ! gost_ec_keygen(EVP_PKEY_get0(sec_key))) {
192             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT,
193                     GOST_R_ERROR_COMPUTING_SHARED_KEY);
194                 goto err;
195             }
196         }
197     }
198     if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS)
199         && param == gost_cipher_list) {
200         param = gost_cipher_list;
201     }
202     if (out) {
203         int dgst_nid = NID_undef;
204         EVP_PKEY_get_default_digest_nid(pubk, &dgst_nid);
205
206         if (!VKO_compute_key(shared_key, 32,
207                              EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)),
208                              EVP_PKEY_get0(sec_key), ukm, dgst_nid)) {
209             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT,
210                     GOST_R_ERROR_COMPUTING_SHARED_KEY);
211             goto err;
212         }
213         gost_init(&cctx, param->sblock);
214         keyWrapCryptoPro(&cctx, shared_key, ukm, key, crypted_key);
215     }
216     gkt = GOST_KEY_TRANSPORT_new();
217     if (!gkt) {
218         goto err;
219     }
220     if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, ukm, 8)) {
221         goto err;
222     }
223     if (!ASN1_OCTET_STRING_set(gkt->key_info->imit, crypted_key + 40, 4)) {
224         goto err;
225     }
226     if (!ASN1_OCTET_STRING_set
227         (gkt->key_info->encrypted_key, crypted_key + 8, 32)) {
228         goto err;
229     }
230     if (key_is_ephemeral) {
231         if (!X509_PUBKEY_set
232             (&gkt->key_agreement_info->ephem_key, out ? sec_key : pubk)) {
233             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT,
234                     GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
235             goto err;
236         }
237     }
238     ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
239     gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
240     if (key_is_ephemeral)
241         EVP_PKEY_free(sec_key);
242     if (!key_is_ephemeral) {
243         /* Set control "public key from client certificate used" */
244         if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL)
245             <= 0) {
246             GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, GOST_R_CTRL_CALL_FAILED);
247             goto err;
248         }
249     }
250     if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0)
251         ret = 1;
252     GOST_KEY_TRANSPORT_free(gkt);
253     return ret;
254  err:
255     if (key_is_ephemeral)
256         EVP_PKEY_free(sec_key);
257     GOST_KEY_TRANSPORT_free(gkt);
258     return -1;
259 }
260
261 /*
262  * EVP_PKEY_METHOD callback decrypt
263  * Implementation of GOST2001 key transport, cryptopo variation
264  */
265 int pkey_GOST_ECcp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
266                            size_t *key_len, const unsigned char *in,
267                            size_t in_len)
268 {
269     const unsigned char *p = in;
270     EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
271     GOST_KEY_TRANSPORT *gkt = NULL;
272     int ret = 0;
273     unsigned char wrappedKey[44];
274     unsigned char sharedKey[32];
275     gost_ctx ctx;
276     const struct gost_cipher_info *param = NULL;
277     EVP_PKEY *eph_key = NULL, *peerkey = NULL;
278     int dgst_nid = NID_undef;
279
280     if (!key) {
281         *key_len = 32;
282         return 1;
283     }
284     gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len);
285     if (!gkt) {
286         GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
287                 GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
288         return -1;
289     }
290
291     /* If key transport structure contains public key, use it */
292     eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
293     if (eph_key) {
294         if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0) {
295             GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
296                     GOST_R_INCOMPATIBLE_PEER_KEY);
297             goto err;
298         }
299     } else {
300         /* Set control "public key from client certificate used" */
301         if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL)
302             <= 0) {
303             GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT, GOST_R_CTRL_CALL_FAILED);
304             goto err;
305         }
306     }
307     peerkey = EVP_PKEY_CTX_get0_peerkey(pctx);
308     if (!peerkey) {
309         GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT, GOST_R_NO_PEER_KEY);
310         goto err;
311     }
312
313     param = get_encryption_params(gkt->key_agreement_info->cipher);
314     if (!param) {
315         goto err;
316     }
317
318     gost_init(&ctx, param->sblock);
319     OPENSSL_assert(gkt->key_agreement_info->eph_iv->length == 8);
320     memcpy(wrappedKey, gkt->key_agreement_info->eph_iv->data, 8);
321     OPENSSL_assert(gkt->key_info->encrypted_key->length == 32);
322     memcpy(wrappedKey + 8, gkt->key_info->encrypted_key->data, 32);
323     OPENSSL_assert(gkt->key_info->imit->length == 4);
324     memcpy(wrappedKey + 40, gkt->key_info->imit->data, 4);
325
326     EVP_PKEY_get_default_digest_nid(priv, &dgst_nid);
327     if (!VKO_compute_key(sharedKey, 32,
328                          EC_KEY_get0_public_key(EVP_PKEY_get0(peerkey)),
329                          EVP_PKEY_get0(priv), wrappedKey, dgst_nid)) {
330         GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
331                 GOST_R_ERROR_COMPUTING_SHARED_KEY);
332         goto err;
333     }
334     if (!keyUnwrapCryptoPro(&ctx, sharedKey, wrappedKey, key)) {
335         GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
336                 GOST_R_ERROR_COMPUTING_SHARED_KEY);
337         goto err;
338     }
339
340     ret = 1;
341  err:
342     EVP_PKEY_free(eph_key);
343     GOST_KEY_TRANSPORT_free(gkt);
344     return ret;
345 }