blob: cfc6bea1e29d6b1d9ff1cd7337d07010e51af203 [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2 * project 2006.
3 */
4/* ====================================================================
5 * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 * software must display the following acknowledgment:
21 * "This product includes software developed by the OpenSSL Project
22 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 * endorse or promote products derived from this software without
26 * prior written permission. For written permission, please contact
27 * licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 * nor may "OpenSSL" appear in their names without prior written
31 * permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 * acknowledgment:
35 * "This product includes software developed by the OpenSSL Project
36 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This product includes cryptographic software written by Eric Young
53 * (eay@cryptsoft.com). This product includes software written by Tim
54 * Hudson (tjh@cryptsoft.com). */
55
56#include <openssl/evp.h>
57
David Benjaminbc5d8ee2015-03-10 16:56:35 -040058#include <limits.h>
Adam Langley2b2d66d2015-01-30 17:08:37 -080059#include <string.h>
60
Adam Langley95c29f32014-06-20 12:00:00 -070061#include <openssl/bn.h>
62#include <openssl/buf.h>
David Benjaminbc5d8ee2015-03-10 16:56:35 -040063#include <openssl/bytestring.h>
Adam Langley95c29f32014-06-20 12:00:00 -070064#include <openssl/digest.h>
65#include <openssl/err.h>
66#include <openssl/mem.h>
David Benjamin98193672016-03-25 18:07:11 -040067#include <openssl/nid.h>
Adam Langley95c29f32014-06-20 12:00:00 -070068#include <openssl/rsa.h>
69
David Benjamin17cf2cb2016-12-13 01:07:13 -050070#include "../internal.h"
Adam Langley96dec442017-05-03 11:50:51 -070071#include "../fipsmodule/rsa/internal.h"
Adam Langley95c29f32014-06-20 12:00:00 -070072#include "internal.h"
73
74
75typedef struct {
David Benjamin808f8322017-08-18 14:06:02 -040076 // Key gen parameters
Adam Langley95c29f32014-06-20 12:00:00 -070077 int nbits;
78 BIGNUM *pub_exp;
David Benjamin808f8322017-08-18 14:06:02 -040079 // RSA padding mode
Adam Langley95c29f32014-06-20 12:00:00 -070080 int pad_mode;
David Benjamin808f8322017-08-18 14:06:02 -040081 // message digest
Adam Langley95c29f32014-06-20 12:00:00 -070082 const EVP_MD *md;
David Benjamin808f8322017-08-18 14:06:02 -040083 // message digest for MGF1
Adam Langley95c29f32014-06-20 12:00:00 -070084 const EVP_MD *mgf1md;
David Benjamin808f8322017-08-18 14:06:02 -040085 // PSS salt length
Adam Langley95c29f32014-06-20 12:00:00 -070086 int saltlen;
David Benjamin808f8322017-08-18 14:06:02 -040087 // tbuf is a buffer which is either NULL, or is the size of the RSA modulus.
88 // It's used to store the output of RSA operations.
Adam Langley95c29f32014-06-20 12:00:00 -070089 uint8_t *tbuf;
David Benjamin808f8322017-08-18 14:06:02 -040090 // OAEP label
Adam Langley95c29f32014-06-20 12:00:00 -070091 uint8_t *oaep_label;
92 size_t oaep_labellen;
93} RSA_PKEY_CTX;
94
David Benjamin8459d062017-09-02 23:45:33 -040095typedef struct {
96 uint8_t *data;
97 size_t len;
98} RSA_OAEP_LABEL_PARAMS;
99
Adam Langley95c29f32014-06-20 12:00:00 -0700100static int pkey_rsa_init(EVP_PKEY_CTX *ctx) {
101 RSA_PKEY_CTX *rctx;
102 rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX));
103 if (!rctx) {
104 return 0;
105 }
David Benjamin17cf2cb2016-12-13 01:07:13 -0500106 OPENSSL_memset(rctx, 0, sizeof(RSA_PKEY_CTX));
Adam Langley95c29f32014-06-20 12:00:00 -0700107
108 rctx->nbits = 2048;
109 rctx->pad_mode = RSA_PKCS1_PADDING;
110 rctx->saltlen = -2;
111
112 ctx->data = rctx;
113
114 return 1;
115}
116
117static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
118 RSA_PKEY_CTX *dctx, *sctx;
119 if (!pkey_rsa_init(dst)) {
120 return 0;
121 }
122 sctx = src->data;
123 dctx = dst->data;
124 dctx->nbits = sctx->nbits;
125 if (sctx->pub_exp) {
126 dctx->pub_exp = BN_dup(sctx->pub_exp);
127 if (!dctx->pub_exp) {
128 return 0;
129 }
130 }
131
132 dctx->pad_mode = sctx->pad_mode;
133 dctx->md = sctx->md;
134 dctx->mgf1md = sctx->mgf1md;
135 if (sctx->oaep_label) {
David Benjamincca4ba72015-04-22 15:49:27 -0400136 OPENSSL_free(dctx->oaep_label);
Adam Langley95c29f32014-06-20 12:00:00 -0700137 dctx->oaep_label = BUF_memdup(sctx->oaep_label, sctx->oaep_labellen);
138 if (!dctx->oaep_label) {
139 return 0;
140 }
141 dctx->oaep_labellen = sctx->oaep_labellen;
142 }
143
144 return 1;
145}
146
147static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) {
148 RSA_PKEY_CTX *rctx = ctx->data;
149
150 if (rctx == NULL) {
151 return;
152 }
153
David Benjamincca4ba72015-04-22 15:49:27 -0400154 BN_free(rctx->pub_exp);
155 OPENSSL_free(rctx->tbuf);
156 OPENSSL_free(rctx->oaep_label);
Adam Langley95c29f32014-06-20 12:00:00 -0700157 OPENSSL_free(rctx);
158}
159
160static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) {
161 if (ctx->tbuf) {
162 return 1;
163 }
164 ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey));
165 if (!ctx->tbuf) {
166 return 0;
167 }
168 return 1;
169}
170
171static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
172 const uint8_t *tbs, size_t tbslen) {
Adam Langley95c29f32014-06-20 12:00:00 -0700173 RSA_PKEY_CTX *rctx = ctx->data;
174 RSA *rsa = ctx->pkey->pkey.rsa;
Adam Langley5129e2d2014-07-25 10:06:44 -0700175 const size_t key_len = EVP_PKEY_size(ctx->pkey);
Adam Langley95c29f32014-06-20 12:00:00 -0700176
David Benjamin9b561e62014-07-09 11:47:42 -0400177 if (!sig) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700178 *siglen = key_len;
David Benjamin9b561e62014-07-09 11:47:42 -0400179 return 1;
Adam Langley5129e2d2014-07-25 10:06:44 -0700180 }
181
182 if (*siglen < key_len) {
David Benjamin3570d732015-06-29 00:28:17 -0400183 OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
David Benjamin9b561e62014-07-09 11:47:42 -0400184 return 0;
185 }
186
Adam Langley95c29f32014-06-20 12:00:00 -0700187 if (rctx->md) {
David Benjamin79d18bc2017-05-02 14:34:09 -0400188 unsigned out_len;
Adam Langley5129e2d2014-07-25 10:06:44 -0700189 switch (rctx->pad_mode) {
190 case RSA_PKCS1_PADDING:
191 if (!RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &out_len, rsa)) {
192 return 0;
193 }
194 *siglen = out_len;
195 return 1;
196
197 case RSA_PKCS1_PSS_PADDING:
David Benjamin79d18bc2017-05-02 14:34:09 -0400198 return RSA_sign_pss_mgf1(rsa, siglen, sig, *siglen, tbs, tbslen,
199 rctx->md, rctx->mgf1md, rctx->saltlen);
Adam Langley5129e2d2014-07-25 10:06:44 -0700200
201 default:
202 return 0;
203 }
Adam Langley95c29f32014-06-20 12:00:00 -0700204 }
205
Adam Langley5129e2d2014-07-25 10:06:44 -0700206 return RSA_sign_raw(rsa, siglen, sig, *siglen, tbs, tbslen, rctx->pad_mode);
Adam Langley95c29f32014-06-20 12:00:00 -0700207}
208
209static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
210 size_t siglen, const uint8_t *tbs,
211 size_t tbslen) {
212 RSA_PKEY_CTX *rctx = ctx->data;
213 RSA *rsa = ctx->pkey->pkey.rsa;
Adam Langley95c29f32014-06-20 12:00:00 -0700214
215 if (rctx->md) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700216 switch (rctx->pad_mode) {
217 case RSA_PKCS1_PADDING:
218 return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa);
Adam Langley95c29f32014-06-20 12:00:00 -0700219
Adam Langley5129e2d2014-07-25 10:06:44 -0700220 case RSA_PKCS1_PSS_PADDING:
David Benjamin79d18bc2017-05-02 14:34:09 -0400221 return RSA_verify_pss_mgf1(rsa, tbs, tbslen, rctx->md, rctx->mgf1md,
222 rctx->saltlen, sig, siglen);
Adam Langley5129e2d2014-07-25 10:06:44 -0700223
224 default:
Adam Langley95c29f32014-06-20 12:00:00 -0700225 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700226 }
227 }
228
David Benjamin79d18bc2017-05-02 14:34:09 -0400229 size_t rslen;
230 const size_t key_len = EVP_PKEY_size(ctx->pkey);
Adam Langley5129e2d2014-07-25 10:06:44 -0700231 if (!setup_tbuf(rctx, ctx) ||
232 !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen,
233 rctx->pad_mode) ||
234 rslen != tbslen ||
235 CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) {
Adam Langley95c29f32014-06-20 12:00:00 -0700236 return 0;
237 }
238
239 return 1;
240}
241
Adam Langleyce9d85e2016-01-24 15:58:39 -0800242static int pkey_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out,
243 size_t *out_len, const uint8_t *sig,
244 size_t sig_len) {
245 RSA_PKEY_CTX *rctx = ctx->data;
246 RSA *rsa = ctx->pkey->pkey.rsa;
247 const size_t key_len = EVP_PKEY_size(ctx->pkey);
248
249 if (out == NULL) {
250 *out_len = key_len;
251 return 1;
252 }
253
254 if (*out_len < key_len) {
255 OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
256 return 0;
257 }
258
Adam Langleyce9d85e2016-01-24 15:58:39 -0800259 if (rctx->md == NULL) {
David Benjamin2baccac2017-05-02 14:54:09 -0400260 return RSA_verify_raw(rsa, out_len, out, *out_len, sig, sig_len,
261 rctx->pad_mode);
Adam Langleyce9d85e2016-01-24 15:58:39 -0800262 }
263
264 if (rctx->pad_mode != RSA_PKCS1_PADDING) {
265 return 0;
266 }
267
David Benjamin808f8322017-08-18 14:06:02 -0400268 // Assemble the encoded hash, using a placeholder hash value.
David Benjamin05821b02017-05-02 14:15:21 -0400269 static const uint8_t kDummyHash[EVP_MAX_MD_SIZE] = {0};
270 const size_t hash_len = EVP_MD_size(rctx->md);
Adam Langleyce9d85e2016-01-24 15:58:39 -0800271 uint8_t *asn1_prefix;
272 size_t asn1_prefix_len;
273 int asn1_prefix_allocated;
David Benjamin2baccac2017-05-02 14:54:09 -0400274 if (!setup_tbuf(rctx, ctx) ||
275 !RSA_add_pkcs1_prefix(&asn1_prefix, &asn1_prefix_len,
David Benjamin05821b02017-05-02 14:15:21 -0400276 &asn1_prefix_allocated, EVP_MD_type(rctx->md),
277 kDummyHash, hash_len)) {
Adam Langleyce9d85e2016-01-24 15:58:39 -0800278 return 0;
279 }
280
281 size_t rslen;
282 int ok = 1;
283 if (!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, sig_len,
284 RSA_PKCS1_PADDING) ||
David Benjamin05821b02017-05-02 14:15:21 -0400285 rslen != asn1_prefix_len ||
David Benjamin808f8322017-08-18 14:06:02 -0400286 // Compare all but the hash suffix.
David Benjamin05821b02017-05-02 14:15:21 -0400287 CRYPTO_memcmp(rctx->tbuf, asn1_prefix, asn1_prefix_len - hash_len) != 0) {
Adam Langleyce9d85e2016-01-24 15:58:39 -0800288 ok = 0;
289 }
290
291 if (asn1_prefix_allocated) {
292 OPENSSL_free(asn1_prefix);
293 }
294
295 if (!ok) {
296 return 0;
297 }
298
Adam Langleyce9d85e2016-01-24 15:58:39 -0800299 if (out != NULL) {
David Benjamin05821b02017-05-02 14:15:21 -0400300 OPENSSL_memcpy(out, rctx->tbuf + rslen - hash_len, hash_len);
Adam Langleyce9d85e2016-01-24 15:58:39 -0800301 }
David Benjamin05821b02017-05-02 14:15:21 -0400302 *out_len = hash_len;
Adam Langleyce9d85e2016-01-24 15:58:39 -0800303
304 return 1;
305}
306
Adam Langley95c29f32014-06-20 12:00:00 -0700307static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
308 const uint8_t *in, size_t inlen) {
Adam Langley95c29f32014-06-20 12:00:00 -0700309 RSA_PKEY_CTX *rctx = ctx->data;
David Benjamin9b561e62014-07-09 11:47:42 -0400310 RSA *rsa = ctx->pkey->pkey.rsa;
Adam Langley5129e2d2014-07-25 10:06:44 -0700311 const size_t key_len = EVP_PKEY_size(ctx->pkey);
David Benjamin9b561e62014-07-09 11:47:42 -0400312
313 if (!out) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700314 *outlen = key_len;
David Benjamin9b561e62014-07-09 11:47:42 -0400315 return 1;
Adam Langley5129e2d2014-07-25 10:06:44 -0700316 }
317
318 if (*outlen < key_len) {
David Benjamin3570d732015-06-29 00:28:17 -0400319 OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
David Benjamin9b561e62014-07-09 11:47:42 -0400320 return 0;
321 }
Adam Langley95c29f32014-06-20 12:00:00 -0700322
323 if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700324 if (!setup_tbuf(rctx, ctx) ||
325 !RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, key_len, in, inlen,
Adam Langley95c29f32014-06-20 12:00:00 -0700326 rctx->oaep_label, rctx->oaep_labellen,
Adam Langley5129e2d2014-07-25 10:06:44 -0700327 rctx->md, rctx->mgf1md) ||
328 !RSA_encrypt(rsa, outlen, out, *outlen, rctx->tbuf, key_len,
329 RSA_NO_PADDING)) {
330 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700331 }
Adam Langley5129e2d2014-07-25 10:06:44 -0700332 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700333 }
334
Adam Langley5129e2d2014-07-25 10:06:44 -0700335 return RSA_encrypt(rsa, outlen, out, *outlen, in, inlen, rctx->pad_mode);
Adam Langley95c29f32014-06-20 12:00:00 -0700336}
337
338static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out,
339 size_t *outlen, const uint8_t *in,
340 size_t inlen) {
Adam Langley95c29f32014-06-20 12:00:00 -0700341 RSA_PKEY_CTX *rctx = ctx->data;
David Benjamin9b561e62014-07-09 11:47:42 -0400342 RSA *rsa = ctx->pkey->pkey.rsa;
Adam Langley5129e2d2014-07-25 10:06:44 -0700343 const size_t key_len = EVP_PKEY_size(ctx->pkey);
David Benjamin9b561e62014-07-09 11:47:42 -0400344
345 if (!out) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700346 *outlen = key_len;
David Benjamin9b561e62014-07-09 11:47:42 -0400347 return 1;
Adam Langley5129e2d2014-07-25 10:06:44 -0700348 }
349
350 if (*outlen < key_len) {
David Benjamin3570d732015-06-29 00:28:17 -0400351 OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
David Benjamin9b561e62014-07-09 11:47:42 -0400352 return 0;
353 }
Adam Langley95c29f32014-06-20 12:00:00 -0700354
355 if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
David Benjaminb0ad3d72017-03-16 13:15:31 -0400356 size_t padded_len;
Adam Langley5129e2d2014-07-25 10:06:44 -0700357 if (!setup_tbuf(rctx, ctx) ||
David Benjaminb0ad3d72017-03-16 13:15:31 -0400358 !RSA_decrypt(rsa, &padded_len, rctx->tbuf, key_len, in, inlen,
359 RSA_NO_PADDING) ||
360 !RSA_padding_check_PKCS1_OAEP_mgf1(
361 out, outlen, key_len, rctx->tbuf, padded_len, rctx->oaep_label,
362 rctx->oaep_labellen, rctx->md, rctx->mgf1md)) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700363 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700364 }
Adam Langley5129e2d2014-07-25 10:06:44 -0700365 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700366 }
367
Adam Langley5129e2d2014-07-25 10:06:44 -0700368 return RSA_decrypt(rsa, outlen, out, key_len, in, inlen, rctx->pad_mode);
Adam Langley95c29f32014-06-20 12:00:00 -0700369}
370
371static int check_padding_md(const EVP_MD *md, int padding) {
372 if (!md) {
373 return 1;
374 }
375
376 if (padding == RSA_NO_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400377 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
Adam Langley95c29f32014-06-20 12:00:00 -0700378 return 0;
379 }
380
381 return 1;
382}
383
384static int is_known_padding(int padding_mode) {
385 switch (padding_mode) {
386 case RSA_PKCS1_PADDING:
Adam Langley95c29f32014-06-20 12:00:00 -0700387 case RSA_NO_PADDING:
388 case RSA_PKCS1_OAEP_PADDING:
389 case RSA_PKCS1_PSS_PADDING:
390 return 1;
391 default:
392 return 0;
393 }
394}
395
396static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
397 RSA_PKEY_CTX *rctx = ctx->data;
398 switch (type) {
399 case EVP_PKEY_CTRL_RSA_PADDING:
400 if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) ||
401 (p1 == RSA_PKCS1_PSS_PADDING &&
402 0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) ||
403 (p1 == RSA_PKCS1_OAEP_PADDING &&
404 0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) {
David Benjamin3570d732015-06-29 00:28:17 -0400405 OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400406 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700407 }
408 if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) &&
409 rctx->md == NULL) {
410 rctx->md = EVP_sha1();
411 }
412 rctx->pad_mode = p1;
413 return 1;
414
415 case EVP_PKEY_CTRL_GET_RSA_PADDING:
416 *(int *)p2 = rctx->pad_mode;
417 return 1;
418
419 case EVP_PKEY_CTRL_RSA_PSS_SALTLEN:
420 case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN:
421 if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400422 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400423 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700424 }
425 if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) {
426 *(int *)p2 = rctx->saltlen;
427 } else {
428 if (p1 < -2) {
David Benjamine0ba4dd2015-03-10 17:10:22 -0400429 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700430 }
431 rctx->saltlen = p1;
432 }
433 return 1;
434
435 case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
436 if (p1 < 256) {
David Benjamin3570d732015-06-29 00:28:17 -0400437 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400438 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700439 }
440 rctx->nbits = p1;
441 return 1;
442
443 case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
444 if (!p2) {
David Benjamine0ba4dd2015-03-10 17:10:22 -0400445 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700446 }
447 BN_free(rctx->pub_exp);
448 rctx->pub_exp = p2;
449 return 1;
450
451 case EVP_PKEY_CTRL_RSA_OAEP_MD:
452 case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
453 if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400454 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400455 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700456 }
457 if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) {
458 *(const EVP_MD **)p2 = rctx->md;
459 } else {
460 rctx->md = p2;
461 }
462 return 1;
463
464 case EVP_PKEY_CTRL_MD:
465 if (!check_padding_md(p2, rctx->pad_mode)) {
466 return 0;
467 }
468 rctx->md = p2;
469 return 1;
470
471 case EVP_PKEY_CTRL_GET_MD:
472 *(const EVP_MD **)p2 = rctx->md;
473 return 1;
474
475 case EVP_PKEY_CTRL_RSA_MGF1_MD:
476 case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
477 if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING &&
478 rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400479 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400480 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700481 }
482 if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
483 if (rctx->mgf1md) {
484 *(const EVP_MD **)p2 = rctx->mgf1md;
485 } else {
486 *(const EVP_MD **)p2 = rctx->md;
487 }
488 } else {
489 rctx->mgf1md = p2;
490 }
491 return 1;
492
David Benjamin8459d062017-09-02 23:45:33 -0400493 case EVP_PKEY_CTRL_RSA_OAEP_LABEL: {
Adam Langley95c29f32014-06-20 12:00:00 -0700494 if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400495 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400496 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700497 }
David Benjamincca4ba72015-04-22 15:49:27 -0400498 OPENSSL_free(rctx->oaep_label);
David Benjamin8459d062017-09-02 23:45:33 -0400499 RSA_OAEP_LABEL_PARAMS *params = p2;
500 rctx->oaep_label = params->data;
501 rctx->oaep_labellen = params->len;
Adam Langley95c29f32014-06-20 12:00:00 -0700502 return 1;
David Benjamin8459d062017-09-02 23:45:33 -0400503 }
Adam Langley95c29f32014-06-20 12:00:00 -0700504
505 case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
506 if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
David Benjamin3570d732015-06-29 00:28:17 -0400507 OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400508 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700509 }
David Benjaminbc5d8ee2015-03-10 16:56:35 -0400510 CBS_init((CBS *)p2, rctx->oaep_label, rctx->oaep_labellen);
511 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700512
Adam Langley95c29f32014-06-20 12:00:00 -0700513 default:
David Benjamin3570d732015-06-29 00:28:17 -0400514 OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
David Benjamine0ba4dd2015-03-10 17:10:22 -0400515 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700516 }
517}
518
519static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
520 RSA *rsa = NULL;
521 RSA_PKEY_CTX *rctx = ctx->data;
522
Adam Langley95c29f32014-06-20 12:00:00 -0700523 if (!rctx->pub_exp) {
524 rctx->pub_exp = BN_new();
David Benjamin6eb000d2015-02-11 01:17:41 -0500525 if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4)) {
Adam Langley95c29f32014-06-20 12:00:00 -0700526 return 0;
David Benjamin6eb000d2015-02-11 01:17:41 -0500527 }
Adam Langley95c29f32014-06-20 12:00:00 -0700528 }
529 rsa = RSA_new();
530 if (!rsa) {
531 return 0;
532 }
533
Adam Langley5129e2d2014-07-25 10:06:44 -0700534 if (!RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, NULL)) {
Adam Langley95c29f32014-06-20 12:00:00 -0700535 RSA_free(rsa);
Adam Langley5129e2d2014-07-25 10:06:44 -0700536 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700537 }
Adam Langley5129e2d2014-07-25 10:06:44 -0700538
539 EVP_PKEY_assign_RSA(pkey, rsa);
540 return 1;
Adam Langley95c29f32014-06-20 12:00:00 -0700541}
542
543const EVP_PKEY_METHOD rsa_pkey_meth = {
Adam Langleyce9d85e2016-01-24 15:58:39 -0800544 EVP_PKEY_RSA,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800545 pkey_rsa_init,
546 pkey_rsa_copy,
547 pkey_rsa_cleanup,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800548 pkey_rsa_keygen,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800549 pkey_rsa_sign,
David Benjamin417830d2017-03-28 15:24:11 -0500550 NULL /* sign_message */,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800551 pkey_rsa_verify,
David Benjamin417830d2017-03-28 15:24:11 -0500552 NULL /* verify_message */,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800553 pkey_rsa_verify_recover,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800554 pkey_rsa_encrypt,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800555 pkey_rsa_decrypt,
Adam Langleyce9d85e2016-01-24 15:58:39 -0800556 0 /* derive */,
557 pkey_rsa_ctrl,
Adam Langley95c29f32014-06-20 12:00:00 -0700558};
559
560int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) {
561 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING,
562 padding, NULL);
563}
564
565int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) {
566 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING,
567 0, out_padding);
568}
569
570int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) {
571 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
572 (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
573 EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL);
574}
575
576int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) {
577 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
578 (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
579 EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len);
580}
581
582int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) {
583 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
584 EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL);
585}
586
587int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) {
588 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
589 EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e);
590}
591
592int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
593 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
594 EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md);
595}
596
597int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
598 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
599 EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md);
600}
601
602int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
603 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
604 EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
605 EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md);
606}
607
608int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
609 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
610 EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
611 EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md);
612}
613
David Benjamin719594e2015-12-25 01:02:37 -0500614int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, uint8_t *label,
Adam Langley95c29f32014-06-20 12:00:00 -0700615 size_t label_len) {
David Benjamin8459d062017-09-02 23:45:33 -0400616 RSA_OAEP_LABEL_PARAMS params = {label, label_len};
Adam Langley95c29f32014-06-20 12:00:00 -0700617 return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
David Benjamin8459d062017-09-02 23:45:33 -0400618 EVP_PKEY_CTRL_RSA_OAEP_LABEL, 0, &params);
Adam Langley95c29f32014-06-20 12:00:00 -0700619}
620
621int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
622 const uint8_t **out_label) {
David Benjaminbc5d8ee2015-03-10 16:56:35 -0400623 CBS label;
David Benjamin7cc29ab2015-03-10 17:16:26 -0400624 if (!EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
625 EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, &label)) {
David Benjaminbc5d8ee2015-03-10 16:56:35 -0400626 return -1;
627 }
628 if (CBS_len(&label) > INT_MAX) {
David Benjamin3570d732015-06-29 00:28:17 -0400629 OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
David Benjaminbc5d8ee2015-03-10 16:56:35 -0400630 return -1;
631 }
632 *out_label = CBS_data(&label);
633 return (int)CBS_len(&label);
Adam Langley95c29f32014-06-20 12:00:00 -0700634}