1 /* $OpenBSD: gostr341001_pmeth.c,v 1.11 2015/02/14 06:40:04 jsing Exp $ */
3 * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
4 * Copyright (c) 2005-2006 Cryptocom LTD
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * 3. All advertising materials mentioning features or use of this
19 * software must display the following acknowledgment:
20 * "This product includes software developed by the OpenSSL Project
21 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
23 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24 * endorse or promote products derived from this software without
25 * prior written permission. For written permission, please contact
26 * openssl-core@openssl.org.
28 * 5. Products derived from this software may not be called "OpenSSL"
29 * nor may "OpenSSL" appear in their names without prior written
30 * permission of the OpenSSL Project.
32 * 6. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by the OpenSSL Project
35 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
37 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48 * OF THE POSSIBILITY OF SUCH DAMAGE.
49 * ====================================================================
54 #include <openssl/opensslconf.h>
56 #ifndef OPENSSL_NO_GOST
57 #include <openssl/bn.h>
58 #include <openssl/evp.h>
59 #include <openssl/err.h>
60 #include <openssl/gost.h>
61 #include <openssl/ec.h>
62 #include <openssl/ecdsa.h>
63 #include <openssl/x509.h>
66 #include "gost_locl.h"
67 #include "gost_asn1.h"
70 unpack_signature_cp(const unsigned char *sig
, size_t siglen
)
76 GOSTerr(GOST_F_UNPACK_SIGNATURE_CP
, ERR_R_MALLOC_FAILURE
);
79 BN_bin2bn(sig
, siglen
/ 2, s
->s
);
80 BN_bin2bn(sig
+ siglen
/ 2, siglen
/ 2, s
->r
);
85 pack_signature_cp(ECDSA_SIG
*s
, int order
, unsigned char *sig
, size_t *siglen
)
87 int r_len
= BN_num_bytes(s
->r
);
88 int s_len
= BN_num_bytes(s
->s
);
90 if (r_len
> order
|| s_len
> order
)
95 memset(sig
, 0, *siglen
);
96 BN_bn2bin(s
->s
, sig
+ order
- s_len
);
97 BN_bn2bin(s
->r
, sig
+ 2 * order
- r_len
);
103 unpack_signature_le(const unsigned char *sig
, size_t siglen
)
109 GOSTerr(GOST_F_UNPACK_SIGNATURE_LE
, ERR_R_MALLOC_FAILURE
);
112 GOST_le2bn(sig
, siglen
/ 2, s
->r
);
113 GOST_le2bn(sig
+ siglen
/ 2, siglen
/ 2, s
->s
);
118 pack_signature_le(ECDSA_SIG
*s
, int order
, unsigned char *sig
, size_t *siglen
)
121 memset(sig
, 0, *siglen
);
122 GOST_bn2le(s
->r
, sig
, order
);
123 GOST_bn2le(s
->s
, sig
+ order
, order
);
128 struct gost_pmeth_data
{
129 int sign_param_nid
; /* Should be set whenever parameters are filled */
132 unsigned char *shared_ukm
;
138 pkey_gost01_init(EVP_PKEY_CTX
*ctx
)
140 struct gost_pmeth_data
*data
;
141 EVP_PKEY
*pkey
= EVP_PKEY_CTX_get0_pkey(ctx
);
143 data
= calloc(1, sizeof(struct gost_pmeth_data
));
147 if (pkey
!= NULL
&& pkey
->pkey
.gost
!= NULL
) {
148 data
->sign_param_nid
=
149 EC_GROUP_get_curve_name(GOST_KEY_get0_group(pkey
->pkey
.gost
));
150 data
->digest_nid
= GOST_KEY_get_digest(pkey
->pkey
.gost
);
152 EVP_PKEY_CTX_set_data(ctx
, data
);
156 /* Copies contents of gost_pmeth_data structure */
158 pkey_gost01_copy(EVP_PKEY_CTX
*dst
, EVP_PKEY_CTX
*src
)
160 struct gost_pmeth_data
*dst_data
, *src_data
;
162 if (pkey_gost01_init(dst
) == 0)
165 src_data
= EVP_PKEY_CTX_get_data(src
);
166 dst_data
= EVP_PKEY_CTX_get_data(dst
);
167 *dst_data
= *src_data
;
168 if (src_data
->shared_ukm
!= NULL
)
169 dst_data
->shared_ukm
= NULL
;
173 /* Frees up gost_pmeth_data structure */
175 pkey_gost01_cleanup(EVP_PKEY_CTX
*ctx
)
177 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(ctx
);
179 free(data
->shared_ukm
);
184 pkey_gost01_paramgen(EVP_PKEY_CTX
*ctx
, EVP_PKEY
*pkey
)
186 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(ctx
);
187 EC_GROUP
*group
= NULL
;
188 GOST_KEY
*gost
= NULL
;
191 if (data
->sign_param_nid
== NID_undef
||
192 data
->digest_nid
== NID_undef
) {
193 GOSTerr(GOST_F_PKEY_GOST01_PARAMGEN
, GOST_R_NO_PARAMETERS_SET
);
197 group
= EC_GROUP_new_by_curve_name(data
->sign_param_nid
);
201 EC_GROUP_set_asn1_flag(group
, OPENSSL_EC_NAMED_CURVE
);
203 gost
= GOST_KEY_new();
207 if (GOST_KEY_set_digest(gost
, data
->digest_nid
) == 0)
210 if (GOST_KEY_set_group(gost
, group
) != 0)
211 ret
= EVP_PKEY_assign_GOST(pkey
, gost
);
216 EC_GROUP_free(group
);
221 pkey_gost01_keygen(EVP_PKEY_CTX
*ctx
, EVP_PKEY
*pkey
)
223 if (pkey_gost01_paramgen(ctx
, pkey
) == 0)
225 return gost2001_keygen(pkey
->pkey
.gost
) != 0;
229 pkey_gost01_sign(EVP_PKEY_CTX
*ctx
, unsigned char *sig
, size_t *siglen
,
230 const unsigned char *tbs
, size_t tbs_len
)
232 ECDSA_SIG
*unpacked_sig
= NULL
;
233 EVP_PKEY
*pkey
= EVP_PKEY_CTX_get0_pkey(ctx
);
234 struct gost_pmeth_data
*pctx
= EVP_PKEY_CTX_get_data(ctx
);
239 if (pkey
== NULL
|| pkey
->pkey
.gost
== NULL
)
241 size
= GOST_KEY_get_size(pkey
->pkey
.gost
);
248 } else if (*siglen
< 2 * size
) {
249 GOSTerr(GOST_F_PKEY_GOST01_SIGN
, EC_R_BUFFER_TOO_SMALL
);
252 if (tbs_len
!= 32 && tbs_len
!= 64) {
253 GOSTerr(GOST_F_PKEY_GOST01_SIGN
, EVP_R_BAD_BLOCK_LENGTH
);
256 md
= GOST_le2bn(tbs
, tbs_len
, NULL
);
259 unpacked_sig
= gost2001_do_sign(md
, pkey
->pkey
.gost
);
261 if (unpacked_sig
== NULL
) {
264 switch (pctx
->sig_format
) {
265 case GOST_SIG_FORMAT_SR_BE
:
266 ret
= pack_signature_cp(unpacked_sig
, size
, sig
, siglen
);
268 case GOST_SIG_FORMAT_RS_LE
:
269 ret
= pack_signature_le(unpacked_sig
, size
, sig
, siglen
);
276 ECDSA_SIG_free(unpacked_sig
);
281 pkey_gost01_verify(EVP_PKEY_CTX
*ctx
, const unsigned char *sig
, size_t siglen
,
282 const unsigned char *tbs
, size_t tbs_len
)
285 EVP_PKEY
*pub_key
= EVP_PKEY_CTX_get0_pkey(ctx
);
286 struct gost_pmeth_data
*pctx
= EVP_PKEY_CTX_get_data(ctx
);
292 switch (pctx
->sig_format
) {
293 case GOST_SIG_FORMAT_SR_BE
:
294 s
= unpack_signature_cp(sig
, siglen
);
296 case GOST_SIG_FORMAT_RS_LE
:
297 s
= unpack_signature_le(sig
, siglen
);
302 md
= GOST_le2bn(tbs
, tbs_len
, NULL
);
305 ok
= gost2001_do_verify(md
, s
, pub_key
->pkey
.gost
);
314 gost01_VKO_key(EVP_PKEY
*pub_key
, EVP_PKEY
*priv_key
, const unsigned char *ukm
,
317 unsigned char hashbuf
[128];
320 BN_CTX
*ctx
= BN_CTX_new();
327 if ((UKM
= BN_CTX_get(ctx
)) == NULL
)
329 if ((X
= BN_CTX_get(ctx
)) == NULL
)
331 if ((Y
= BN_CTX_get(ctx
)) == NULL
)
334 GOST_le2bn(ukm
, 8, UKM
);
336 digest_nid
= GOST_KEY_get_digest(priv_key
->pkey
.gost
);
337 if (VKO_compute_key(X
, Y
, pub_key
->pkey
.gost
, priv_key
->pkey
.gost
,
341 switch (digest_nid
) {
342 case NID_id_GostR3411_94_CryptoProParamSet
:
343 GOST_bn2le(X
, hashbuf
, 32);
344 GOST_bn2le(Y
, hashbuf
+ 32, 32);
345 GOSTR341194(hashbuf
, 64, key
, digest_nid
);
348 case NID_id_tc26_gost3411_2012_256
:
349 GOST_bn2le(X
, hashbuf
, 32);
350 GOST_bn2le(Y
, hashbuf
+ 32, 32);
351 STREEBOG256(hashbuf
, 64, key
);
354 case NID_id_tc26_gost3411_2012_512
:
355 GOST_bn2le(X
, hashbuf
, 64);
356 GOST_bn2le(Y
, hashbuf
+ 64, 64);
357 STREEBOG256(hashbuf
, 128, key
);
371 pkey_gost01_decrypt(EVP_PKEY_CTX
*pctx
, unsigned char *key
, size_t *key_len
,
372 const unsigned char *in
, size_t in_len
)
374 const unsigned char *p
= in
;
375 EVP_PKEY
*priv
= EVP_PKEY_CTX_get0_pkey(pctx
);
376 GOST_KEY_TRANSPORT
*gkt
= NULL
;
378 unsigned char wrappedKey
[44];
379 unsigned char sharedKey
[32];
380 EVP_PKEY
*eph_key
= NULL
, *peerkey
= NULL
;
387 gkt
= d2i_GOST_KEY_TRANSPORT(NULL
, (const unsigned char **)&p
, in_len
);
389 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
390 GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO
);
394 /* If key transport structure contains public key, use it */
395 eph_key
= X509_PUBKEY_get(gkt
->key_agreement_info
->ephem_key
);
396 if (eph_key
!= NULL
) {
397 if (EVP_PKEY_derive_set_peer(pctx
, eph_key
) <= 0) {
398 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
399 GOST_R_INCOMPATIBLE_PEER_KEY
);
403 /* Set control "public key from client certificate used" */
404 if (EVP_PKEY_CTX_ctrl(pctx
, -1, -1, EVP_PKEY_CTRL_PEER_KEY
, 3,
406 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
407 GOST_R_CTRL_CALL_FAILED
);
411 peerkey
= EVP_PKEY_CTX_get0_peerkey(pctx
);
412 if (peerkey
== NULL
) {
413 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
, GOST_R_NO_PEER_KEY
);
417 nid
= OBJ_obj2nid(gkt
->key_agreement_info
->cipher
);
419 if (gkt
->key_agreement_info
->eph_iv
->length
!= 8) {
420 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
421 GOST_R_INVALID_IV_LENGTH
);
424 memcpy(wrappedKey
, gkt
->key_agreement_info
->eph_iv
->data
, 8);
425 if (gkt
->key_info
->encrypted_key
->length
!= 32) {
426 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
427 EVP_R_BAD_KEY_LENGTH
);
430 memcpy(wrappedKey
+ 8, gkt
->key_info
->encrypted_key
->data
, 32);
431 if (gkt
->key_info
->imit
->length
!= 4) {
432 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
433 ERR_R_INTERNAL_ERROR
);
436 memcpy(wrappedKey
+ 40, gkt
->key_info
->imit
->data
, 4);
437 if (gost01_VKO_key(peerkey
, priv
, wrappedKey
, sharedKey
) <= 0)
439 if (gost_key_unwrap_crypto_pro(nid
, sharedKey
, wrappedKey
, key
) == 0) {
440 GOSTerr(GOST_F_PKEY_GOST01_DECRYPT
,
441 GOST_R_ERROR_COMPUTING_SHARED_KEY
);
447 EVP_PKEY_free(eph_key
);
448 GOST_KEY_TRANSPORT_free(gkt
);
453 pkey_gost01_derive(EVP_PKEY_CTX
*ctx
, unsigned char *key
, size_t *keylen
)
456 * Public key of peer in the ctx field peerkey
457 * Our private key in the ctx pkey
458 * ukm is in the algorithm specific context data
460 EVP_PKEY
*my_key
= EVP_PKEY_CTX_get0_pkey(ctx
);
461 EVP_PKEY
*peer_key
= EVP_PKEY_CTX_get0_peerkey(ctx
);
462 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(ctx
);
464 if (data
->shared_ukm
== NULL
) {
465 GOSTerr(GOST_F_PKEY_GOST01_DERIVE
, GOST_R_UKM_NOT_SET
);
474 if (gost01_VKO_key(peer_key
, my_key
, data
->shared_ukm
, key
) <= 0)
482 pkey_gost01_encrypt(EVP_PKEY_CTX
*pctx
, unsigned char *out
, size_t *out_len
,
483 const unsigned char *key
, size_t key_len
)
485 GOST_KEY_TRANSPORT
*gkt
= NULL
;
486 EVP_PKEY
*pubk
= EVP_PKEY_CTX_get0_pkey(pctx
);
487 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(pctx
);
488 unsigned char ukm
[8], shared_key
[32], crypted_key
[44];
490 int key_is_ephemeral
;
491 EVP_PKEY
*sec_key
= EVP_PKEY_CTX_get0_peerkey(pctx
);
492 int nid
= NID_id_Gost28147_89_CryptoPro_A_ParamSet
;
494 if (data
->shared_ukm
!= NULL
) {
495 memcpy(ukm
, data
->shared_ukm
, 8);
496 } else /* if (out != NULL) */ {
497 arc4random_buf(ukm
, 8);
499 /* Check for private key in the peer_key of context */
501 key_is_ephemeral
= 0;
502 if (GOST_KEY_get0_private_key(sec_key
->pkey
.gost
) == 0) {
503 GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT
,
504 GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR
);
508 key_is_ephemeral
= 1;
512 sec_key
= EVP_PKEY_new();
515 tmp_key
= GOST_KEY_new();
518 if (EVP_PKEY_assign(sec_key
, EVP_PKEY_base_id(pubk
),
520 GOST_KEY_free(tmp_key
);
523 if (EVP_PKEY_copy_parameters(sec_key
, pubk
) == 0)
525 if (gost2001_keygen(sec_key
->pkey
.gost
) == 0) {
532 if (gost01_VKO_key(pubk
, sec_key
, ukm
, shared_key
) <= 0)
534 gost_key_wrap_crypto_pro(nid
, shared_key
, ukm
, key
,
537 gkt
= GOST_KEY_TRANSPORT_new();
540 if (ASN1_OCTET_STRING_set(gkt
->key_agreement_info
->eph_iv
, ukm
, 8) == 0)
542 if (ASN1_OCTET_STRING_set(gkt
->key_info
->imit
, crypted_key
+ 40,
545 if (ASN1_OCTET_STRING_set(gkt
->key_info
->encrypted_key
, crypted_key
+ 8,
548 if (key_is_ephemeral
) {
549 if (X509_PUBKEY_set(&gkt
->key_agreement_info
->ephem_key
,
550 out
!= NULL
? sec_key
: pubk
) == 0) {
551 GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT
,
552 GOST_R_CANNOT_PACK_EPHEMERAL_KEY
);
556 ASN1_OBJECT_free(gkt
->key_agreement_info
->cipher
);
557 gkt
->key_agreement_info
->cipher
= OBJ_nid2obj(nid
);
558 if (key_is_ephemeral
)
559 EVP_PKEY_free(sec_key
);
561 /* Set control "public key from client certificate used" */
562 if (EVP_PKEY_CTX_ctrl(pctx
, -1, -1, EVP_PKEY_CTRL_PEER_KEY
, 3,
564 GOSTerr(GOST_F_PKEY_GOST01_ENCRYPT
,
565 GOST_R_CTRL_CALL_FAILED
);
569 if ((*out_len
= i2d_GOST_KEY_TRANSPORT(gkt
, out
? &out
: NULL
)) > 0)
571 GOST_KEY_TRANSPORT_free(gkt
);
575 if (key_is_ephemeral
)
576 EVP_PKEY_free(sec_key
);
577 GOST_KEY_TRANSPORT_free(gkt
);
583 pkey_gost01_ctrl(EVP_PKEY_CTX
*ctx
, int type
, int p1
, void *p2
)
585 struct gost_pmeth_data
*pctx
= EVP_PKEY_CTX_get_data(ctx
);
588 case EVP_PKEY_CTRL_MD
:
589 if (EVP_MD_type(p2
) !=
590 GostR3410_get_md_digest(pctx
->digest_nid
)) {
591 GOSTerr(GOST_F_PKEY_GOST01_CTRL
,
592 GOST_R_INVALID_DIGEST_TYPE
);
597 case EVP_PKEY_CTRL_PKCS7_ENCRYPT
:
598 case EVP_PKEY_CTRL_PKCS7_DECRYPT
:
599 case EVP_PKEY_CTRL_PKCS7_SIGN
:
600 case EVP_PKEY_CTRL_DIGESTINIT
:
601 #ifndef OPENSSL_NO_CMS
602 case EVP_PKEY_CTRL_CMS_ENCRYPT
:
603 case EVP_PKEY_CTRL_CMS_DECRYPT
:
604 case EVP_PKEY_CTRL_CMS_SIGN
:
608 case EVP_PKEY_CTRL_GOST_PARAMSET
:
609 pctx
->sign_param_nid
= (int)p1
;
612 case EVP_PKEY_CTRL_SET_IV
:
614 char *ukm
= malloc(p1
);
617 GOSTerr(GOST_F_PKEY_GOST01_CTRL
,
618 ERR_R_MALLOC_FAILURE
);
622 free(pctx
->shared_ukm
);
623 pctx
->shared_ukm
= ukm
;
627 case EVP_PKEY_CTRL_PEER_KEY
:
628 if (p1
== 0 || p1
== 1) /* call from EVP_PKEY_derive_set_peer */
630 if (p1
== 2) /* TLS: peer key used? */
631 return pctx
->peer_key_used
;
632 if (p1
== 3) /* TLS: peer key used! */
633 return (pctx
->peer_key_used
= 1);
635 case EVP_PKEY_CTRL_GOST_SIG_FORMAT
:
637 case GOST_SIG_FORMAT_SR_BE
:
638 case GOST_SIG_FORMAT_RS_LE
:
639 pctx
->sig_format
= p1
;
645 case EVP_PKEY_CTRL_GOST_SET_DIGEST
:
646 pctx
->digest_nid
= (int)p1
;
648 case EVP_PKEY_CTRL_GOST_GET_DIGEST
:
649 *(int *)p2
= pctx
->digest_nid
;
657 pkey_gost01_ctrl_str(EVP_PKEY_CTX
*ctx
, const char *type
, const char *value
)
659 int param_nid
= NID_undef
;
660 int digest_nid
= NID_undef
;
662 if (strcmp(type
, "paramset") == 0) {
665 if (pkey_gost01_ctrl(ctx
, EVP_PKEY_CTRL_GOST_GET_DIGEST
, 0,
668 if (digest_nid
== NID_id_tc26_gost3411_2012_512
)
669 param_nid
= GostR3410_512_param_id(value
);
671 param_nid
= GostR3410_256_param_id(value
);
672 if (param_nid
== NID_undef
)
673 param_nid
= OBJ_txt2nid(value
);
674 if (param_nid
== NID_undef
)
677 return pkey_gost01_ctrl(ctx
, EVP_PKEY_CTRL_GOST_PARAMSET
,
680 if (strcmp(type
, "dgst") == 0) {
683 else if (strcmp(value
, "gost94") == 0 ||
684 strcmp(value
, "md_gost94") == 0)
685 digest_nid
= NID_id_GostR3411_94_CryptoProParamSet
;
686 else if (strcmp(value
, "streebog256") == 0)
687 digest_nid
= NID_id_tc26_gost3411_2012_256
;
688 else if (strcmp(value
, "streebog512") == 0)
689 digest_nid
= NID_id_tc26_gost3411_2012_512
;
691 if (digest_nid
== NID_undef
)
694 return pkey_gost01_ctrl(ctx
, EVP_PKEY_CTRL_GOST_SET_DIGEST
,
700 const EVP_PKEY_METHOD gostr01_pkey_meth
= {
701 .pkey_id
= EVP_PKEY_GOSTR01
,
703 .init
= pkey_gost01_init
,
704 .copy
= pkey_gost01_copy
,
705 .cleanup
= pkey_gost01_cleanup
,
707 .paramgen
= pkey_gost01_paramgen
,
708 .keygen
= pkey_gost01_keygen
,
709 .sign
= pkey_gost01_sign
,
710 .verify
= pkey_gost01_verify
,
712 .encrypt
= pkey_gost01_encrypt
,
713 .decrypt
= pkey_gost01_decrypt
,
714 .derive
= pkey_gost01_derive
,
716 .ctrl
= pkey_gost01_ctrl
,
717 .ctrl_str
= pkey_gost01_ctrl_str
,