1 /* Copyright (c) 2019, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/evp.h>
16 
17 #include <openssl/bytestring.h>
18 #include <openssl/curve25519.h>
19 #include <openssl/err.h>
20 #include <openssl/mem.h>
21 
22 #include "internal.h"
23 #include "../internal.h"
24 
25 
x25519_free(EVP_PKEY * pkey)26 static void x25519_free(EVP_PKEY *pkey) {
27   OPENSSL_free(pkey->pkey.ptr);
28   pkey->pkey.ptr = NULL;
29 }
30 
x25519_set_priv_raw(EVP_PKEY * pkey,const uint8_t * in,size_t len)31 static int x25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
32   if (len != 32) {
33     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
34     return 0;
35   }
36 
37   X25519_KEY *key = OPENSSL_malloc(sizeof(X25519_KEY));
38   if (key == NULL) {
39     OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
40     return 0;
41   }
42 
43   OPENSSL_memcpy(key->priv, in, 32);
44   X25519_public_from_private(key->pub, key->priv);
45   key->has_private = 1;
46 
47   x25519_free(pkey);
48   pkey->pkey.ptr = key;
49   return 1;
50 }
51 
x25519_set_pub_raw(EVP_PKEY * pkey,const uint8_t * in,size_t len)52 static int x25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
53   if (len != 32) {
54     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
55     return 0;
56   }
57 
58   X25519_KEY *key = OPENSSL_malloc(sizeof(X25519_KEY));
59   if (key == NULL) {
60     OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
61     return 0;
62   }
63 
64   OPENSSL_memcpy(key->pub, in, 32);
65   key->has_private = 0;
66 
67   x25519_free(pkey);
68   pkey->pkey.ptr = key;
69   return 1;
70 }
71 
x25519_get_priv_raw(const EVP_PKEY * pkey,uint8_t * out,size_t * out_len)72 static int x25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
73                                 size_t *out_len) {
74   const X25519_KEY *key = pkey->pkey.ptr;
75   if (!key->has_private) {
76     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
77     return 0;
78   }
79 
80   if (out == NULL) {
81     *out_len = 32;
82     return 1;
83   }
84 
85   if (*out_len < 32) {
86     OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
87     return 0;
88   }
89 
90   OPENSSL_memcpy(out, key->priv, 32);
91   *out_len = 32;
92   return 1;
93 }
94 
x25519_get_pub_raw(const EVP_PKEY * pkey,uint8_t * out,size_t * out_len)95 static int x25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
96                                size_t *out_len) {
97   const X25519_KEY *key = pkey->pkey.ptr;
98   if (out == NULL) {
99     *out_len = 32;
100     return 1;
101   }
102 
103   if (*out_len < 32) {
104     OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
105     return 0;
106   }
107 
108   OPENSSL_memcpy(out, key->pub, 32);
109   *out_len = 32;
110   return 1;
111 }
112 
x25519_pub_decode(EVP_PKEY * out,CBS * params,CBS * key)113 static int x25519_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
114   // See RFC 8410, section 4.
115 
116   // The parameters must be omitted. Public keys have length 32.
117   if (CBS_len(params) != 0) {
118     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
119     return 0;
120   }
121 
122   return x25519_set_pub_raw(out, CBS_data(key), CBS_len(key));
123 }
124 
x25519_pub_encode(CBB * out,const EVP_PKEY * pkey)125 static int x25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
126   const X25519_KEY *key = pkey->pkey.ptr;
127 
128   // See RFC 8410, section 4.
129   CBB spki, algorithm, oid, key_bitstring;
130   if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
131       !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
132       !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
133       !CBB_add_bytes(&oid, x25519_asn1_meth.oid, x25519_asn1_meth.oid_len) ||
134       !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
135       !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
136       !CBB_add_bytes(&key_bitstring, key->pub, 32) ||
137       !CBB_flush(out)) {
138     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
139     return 0;
140   }
141 
142   return 1;
143 }
144 
x25519_pub_cmp(const EVP_PKEY * a,const EVP_PKEY * b)145 static int x25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
146   const X25519_KEY *a_key = a->pkey.ptr;
147   const X25519_KEY *b_key = b->pkey.ptr;
148   return OPENSSL_memcmp(a_key->pub, b_key->pub, 32) == 0;
149 }
150 
x25519_priv_decode(EVP_PKEY * out,CBS * params,CBS * key)151 static int x25519_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
152   // See RFC 8410, section 7.
153 
154   // Parameters must be empty. The key is a 32-byte value wrapped in an extra
155   // OCTET STRING layer.
156   CBS inner;
157   if (CBS_len(params) != 0 ||
158       !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) ||
159       CBS_len(key) != 0) {
160     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
161     return 0;
162   }
163 
164   return x25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner));
165 }
166 
x25519_priv_encode(CBB * out,const EVP_PKEY * pkey)167 static int x25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
168   X25519_KEY *key = pkey->pkey.ptr;
169   if (!key->has_private) {
170     OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
171     return 0;
172   }
173 
174   // See RFC 8410, section 7.
175   CBB pkcs8, algorithm, oid, private_key, inner;
176   if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
177       !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
178       !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
179       !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
180       !CBB_add_bytes(&oid, x25519_asn1_meth.oid, x25519_asn1_meth.oid_len) ||
181       !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
182       !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
183       // The PKCS#8 encoding stores only the 32-byte seed which is the first 32
184       // bytes of the private key.
185       !CBB_add_bytes(&inner, key->priv, 32) ||
186       !CBB_flush(out)) {
187     OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
188     return 0;
189   }
190 
191   return 1;
192 }
193 
x25519_size(const EVP_PKEY * pkey)194 static int x25519_size(const EVP_PKEY *pkey) { return 32; }
195 
x25519_bits(const EVP_PKEY * pkey)196 static int x25519_bits(const EVP_PKEY *pkey) { return 253; }
197 
198 const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = {
199     EVP_PKEY_X25519,
200     {0x2b, 0x65, 0x6e},
201     3,
202     x25519_pub_decode,
203     x25519_pub_encode,
204     x25519_pub_cmp,
205     x25519_priv_decode,
206     x25519_priv_encode,
207     x25519_set_priv_raw,
208     x25519_set_pub_raw,
209     x25519_get_priv_raw,
210     x25519_get_pub_raw,
211     NULL /* pkey_opaque */,
212     x25519_size,
213     x25519_bits,
214     NULL /* param_missing */,
215     NULL /* param_copy */,
216     NULL /* param_cmp */,
217     x25519_free,
218 };
219 
EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY * pkey,const uint8_t * in,size_t len)220 int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
221                                    size_t len) {
222   // TODO(davidben): In OpenSSL, this function also works for |EVP_PKEY_EC|
223   // keys. Add support if it ever comes up.
224   if (pkey->type != EVP_PKEY_X25519) {
225     OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
226     return 0;
227   }
228 
229   return x25519_set_pub_raw(pkey, in, len);
230 }
231 
EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY * pkey,uint8_t ** out_ptr)232 size_t EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY *pkey, uint8_t **out_ptr) {
233   // TODO(davidben): In OpenSSL, this function also works for |EVP_PKEY_EC|
234   // keys. Add support if it ever comes up.
235   if (pkey->type != EVP_PKEY_X25519) {
236     OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
237     return 0;
238   }
239 
240   const X25519_KEY *key = pkey->pkey.ptr;
241   if (key == NULL) {
242     OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
243     return 0;
244   }
245 
246   *out_ptr = OPENSSL_memdup(key->pub, 32);
247   return *out_ptr == NULL ? 0 : 32;
248 }
249