X25519 public key methods
[openssl.git] / crypto / ec / ecx_meth.c
1 /*
2  * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include "internal/cryptlib.h"
12 #include <openssl/x509.h>
13 #include <openssl/ec.h>
14 #include <openssl/rand.h>
15 #include "internal/asn1_int.h"
16 #include "internal/evp_int.h"
17 #include "ec_lcl.h"
18
19 #define X25519_KEYLEN        32
20 #define X25519_BITS          253
21 #define X25519_SECURITY_BITS 128
22
23 typedef struct {
24     unsigned char pubkey[X25519_KEYLEN];
25     unsigned char *privkey;
26 } X25519_KEY;
27
28 typedef enum {
29     X25519_PUBLIC,
30     X25519_PRIVATE,
31     X25519_KEYGEN
32 } ecx_key_op_t;
33
34 /* Setup EVP_PKEY using public, private or generation */
35 static int ecx_key_op(EVP_PKEY *pkey, X509_ALGOR *palg,
36                       const unsigned char *p, int plen, ecx_key_op_t op)
37 {
38     int ptype;
39     X25519_KEY *xkey = NULL;
40
41     if (op != X25519_KEYGEN) {
42         /* Algorithm parameters must be absent */
43         X509_ALGOR_get0(NULL, &ptype, NULL, palg);
44         if (ptype != V_ASN1_UNDEF) {
45             ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
46             return 0;
47         }
48
49         if (p == NULL || plen != X25519_KEYLEN) {
50             ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
51             return 0;
52         }
53     }
54
55     xkey = OPENSSL_zalloc(sizeof(*xkey));
56     if (xkey == NULL) {
57         ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
58         return 0;
59     }
60
61     if (op == X25519_PUBLIC) {
62         memcpy(xkey->pubkey, p, plen);
63     } else {
64         xkey->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
65         if (xkey->privkey == NULL) {
66             ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
67             OPENSSL_free(xkey);
68             return 0;
69         }
70         if (op == X25519_KEYGEN) {
71             if (RAND_bytes(xkey->privkey, X25519_KEYLEN) <= 0) {
72                 OPENSSL_secure_free(xkey->privkey);
73                 OPENSSL_free(xkey);
74                 return 0;
75             }
76             xkey->privkey[0] &= 248;
77             xkey->privkey[31] &= 127;
78             xkey->privkey[31] |= 64;
79         } else {
80             memcpy(xkey->privkey, p, X25519_KEYLEN);
81         }
82         X25519_public_from_private(xkey->pubkey, xkey->privkey);
83     }
84
85     EVP_PKEY_assign(pkey, NID_X25519, xkey);
86     return 1;
87 }
88
89 static int ecx_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
90 {
91     const X25519_KEY *xkey = pkey->pkey.ptr;
92     unsigned char *penc;
93
94     if (xkey == NULL) {
95         ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY);
96         return 0;
97     }
98
99     penc = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
100     if (penc == NULL) {
101         ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
102         return 0;
103     }
104
105     if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(NID_X25519), V_ASN1_UNDEF,
106                                 NULL, penc, X25519_KEYLEN)) {
107         OPENSSL_free(penc);
108         ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
109         return 0;
110     }
111     return 1;
112 }
113
114 static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
115 {
116     const unsigned char *p;
117     int pklen;
118     X509_ALGOR *palg;
119
120     if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
121         return 0;
122     return ecx_key_op(pkey, palg, p, pklen, X25519_PUBLIC);
123 }
124
125 static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
126 {
127     const X25519_KEY *akey = a->pkey.ptr;
128     const X25519_KEY *bkey = b->pkey.ptr;
129
130     if (akey == NULL || bkey == NULL)
131         return -2;
132     return !CRYPTO_memcmp(akey->pubkey, bkey->pubkey, X25519_KEYLEN);
133 }
134
135 static int ecx_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
136 {
137     const unsigned char *p;
138     int plen;
139     ASN1_OCTET_STRING *oct = NULL;
140     X509_ALGOR *palg;
141     int rv;
142
143     if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8))
144         return 0;
145
146     oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen);
147     if (oct == NULL) {
148         p = NULL;
149         plen = 0;
150     } else {
151         p = ASN1_STRING_data(oct);
152         plen = ASN1_STRING_length(oct);
153     }
154
155     rv = ecx_key_op(pkey, palg, p, plen, X25519_PRIVATE);
156     ASN1_OCTET_STRING_free(oct);
157     return rv;
158 }
159
160 static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
161 {
162     const X25519_KEY *xkey = pkey->pkey.ptr;
163     ASN1_OCTET_STRING oct;
164     unsigned char *penc = NULL;
165     int penclen;
166
167     if (xkey == NULL || xkey->privkey == NULL) {
168         ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY);
169         return 0;
170     }
171
172     oct.data = xkey->privkey;
173     oct.length = X25519_KEYLEN;
174     oct.flags = 0;
175
176     penclen = i2d_ASN1_OCTET_STRING(&oct, &penc);
177     if (penclen < 0) {
178         ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
179         return 0;
180     }
181
182     if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X25519), 0,
183                          V_ASN1_UNDEF, NULL, penc, penclen)) {
184         OPENSSL_clear_free(penc, penclen);
185         ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
186         return 0;
187     }
188
189     return 1;
190 }
191
192 static int ecx_size(const EVP_PKEY *pkey)
193 {
194     return X25519_KEYLEN;
195 }
196
197 static int ecx_bits(const EVP_PKEY *pkey)
198 {
199     return X25519_BITS;
200 }
201
202 static int ecx_security_bits(const EVP_PKEY *pkey)
203 {
204     return X25519_SECURITY_BITS;
205 }
206
207 static void ecx_free(EVP_PKEY *pkey)
208 {
209     X25519_KEY *xkey = pkey->pkey.ptr;
210
211     if (xkey)
212         OPENSSL_secure_free(xkey->privkey);
213     OPENSSL_free(xkey);
214 }
215
216 /* "parameters" are always equal */
217 static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
218 {
219     return 1;
220 }
221
222 static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
223                          ASN1_PCTX *ctx, ecx_key_op_t op)
224 {
225     const X25519_KEY *xkey = pkey->pkey.ptr;
226
227     if (op == X25519_PRIVATE) {
228         if (xkey == NULL || xkey->privkey == NULL) {
229             if (BIO_printf(bp, "%*s<INVALID PRIVATE KEY>\n", indent, "") <= 0)
230                 return 0;
231             return 1;
232         }
233         if (BIO_printf(bp, "%*sX25519 Private-Key:\n", indent, "") <= 0)
234             return 0;
235         if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0)
236             return 0;
237         if (ASN1_buf_print(bp, xkey->privkey, X25519_KEYLEN, indent + 4) == 0)
238             return 0;
239     } else {
240         if (xkey == NULL) {
241             if (BIO_printf(bp, "%*s<INVALID PUBLIC KEY>\n", indent, "") <= 0)
242                 return 0;
243             return 1;
244         }
245         if (BIO_printf(bp, "%*sX25519 Public-Key:\n", indent, "") <= 0)
246             return 0;
247     }
248     if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0)
249         return 0;
250     if (ASN1_buf_print(bp, xkey->pubkey, X25519_KEYLEN, indent + 4) == 0)
251         return 0;
252     return 1;
253 }
254
255 static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
256                           ASN1_PCTX *ctx)
257 {
258     return ecx_key_print(bp, pkey, indent, ctx, X25519_PRIVATE);
259 }
260
261 static int ecx_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
262                          ASN1_PCTX *ctx)
263 {
264     return ecx_key_print(bp, pkey, indent, ctx, X25519_PUBLIC);
265 }
266
267 static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
268 {
269     return -2;
270 }
271
272 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
273     NID_X25519,
274     NID_X25519,
275     0,
276     "X25519",
277     "OpenSSL X25519 algorithm",
278
279     ecx_pub_decode,
280     ecx_pub_encode,
281     ecx_pub_cmp,
282     ecx_pub_print,
283
284     ecx_priv_decode,
285     ecx_priv_encode,
286     ecx_priv_print,
287
288     ecx_size,
289     ecx_bits,
290     ecx_security_bits,
291
292     0, 0, 0, 0,
293     ecx_cmp_parameters,
294     0, 0,
295
296     ecx_free,
297     ecx_ctrl,
298     NULL,
299     NULL
300 };
301
302 static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
303 {
304     return ecx_key_op(pkey, NULL, NULL, 0, X25519_KEYGEN);
305 }
306
307 static int pkey_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
308                            size_t *keylen)
309 {
310     const X25519_KEY *pkey, *peerkey;
311
312     if (ctx->pkey == NULL || ctx->peerkey == NULL) {
313         ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_KEYS_NOT_SET);
314         return 0;
315     }
316     pkey = ctx->pkey->pkey.ptr;
317     peerkey = ctx->peerkey->pkey.ptr;
318     if (pkey == NULL || pkey->privkey == NULL) {
319         ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY);
320         return 0;
321     }
322     if (peerkey == NULL) {
323         ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PEER_KEY);
324         return 0;
325     }
326     *keylen = X25519_KEYLEN;
327     if (key != NULL && X25519(key, pkey->privkey, peerkey->pubkey) == 0)
328         return 0;
329     return 1;
330 }
331
332 static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
333 {
334     /* Only need to handle peer key for derivation */
335     if (type == EVP_PKEY_CTRL_PEER_KEY)
336         return 1;
337     return -2;
338 }
339
340 const EVP_PKEY_METHOD ecx25519_pkey_meth = {
341     NID_X25519,
342     0, 0, 0, 0, 0, 0, 0,
343     pkey_ecx_keygen,
344     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
345     pkey_ecx_derive,
346     pkey_ecx_ctrl,
347     0
348 };