1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 #include <openssl/evp.h>
17 #include <openssl/rsa.h>
18
19 #include "error/s2n_errno.h"
20
21 #include "stuffer/s2n_stuffer.h"
22
23 #include "crypto/s2n_hash.h"
24 #include "crypto/s2n_rsa_pss.h"
25 #include "crypto/s2n_rsa_signing.h"
26 #include "crypto/s2n_pkey.h"
27
28 #include "utils/s2n_blob.h"
29 #include "utils/s2n_safety.h"
30
31 static int s2n_hash_alg_to_NID[] = {
32 [S2N_HASH_MD5_SHA1] = NID_md5_sha1,
33 [S2N_HASH_SHA1] = NID_sha1,
34 [S2N_HASH_SHA224] = NID_sha224,
35 [S2N_HASH_SHA256] = NID_sha256,
36 [S2N_HASH_SHA384] = NID_sha384,
37 [S2N_HASH_SHA512] = NID_sha512 };
38
s2n_hash_NID_type(s2n_hash_algorithm alg,int * out)39 int s2n_hash_NID_type(s2n_hash_algorithm alg, int *out)
40 {
41 switch(alg) {
42 case S2N_HASH_MD5_SHA1:
43 case S2N_HASH_SHA1:
44 case S2N_HASH_SHA224:
45 case S2N_HASH_SHA256:
46 case S2N_HASH_SHA384:
47 case S2N_HASH_SHA512:
48 *out = s2n_hash_alg_to_NID[alg];
49 break;
50 default:
51 POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM);
52 }
53 return 0;
54 }
55
s2n_rsa_pkcs1v15_sign_digest(const struct s2n_pkey * priv,s2n_hash_algorithm hash_alg,struct s2n_blob * digest,struct s2n_blob * signature)56 int s2n_rsa_pkcs1v15_sign_digest(const struct s2n_pkey *priv, s2n_hash_algorithm hash_alg,
57 struct s2n_blob *digest, struct s2n_blob *signature)
58 {
59 POSIX_ENSURE_REF(priv);
60 POSIX_ENSURE_REF(digest);
61 POSIX_ENSURE_REF(signature);
62
63 int NID_type = 0;
64 POSIX_GUARD(s2n_hash_NID_type(hash_alg, &NID_type));
65
66 const s2n_rsa_private_key *key = &priv->key.rsa_key;
67
68 unsigned int signature_size = signature->size;
69 POSIX_GUARD_OSSL(RSA_sign(NID_type, digest->data, digest->size, signature->data, &signature_size, key->rsa), S2N_ERR_SIGN);
70 POSIX_ENSURE(signature_size <= signature->size, S2N_ERR_SIZE_MISMATCH);
71 signature->size = signature_size;
72
73 return S2N_SUCCESS;
74 }
75
s2n_rsa_pkcs1v15_sign(const struct s2n_pkey * priv,struct s2n_hash_state * digest,struct s2n_blob * signature)76 int s2n_rsa_pkcs1v15_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature)
77 {
78 POSIX_ENSURE_REF(digest);
79
80 uint8_t digest_length = 0;
81 POSIX_GUARD(s2n_hash_digest_size(digest->alg, &digest_length));
82 POSIX_ENSURE_LTE(digest_length, S2N_MAX_DIGEST_LEN);
83
84 uint8_t digest_out[S2N_MAX_DIGEST_LEN] = { 0 };
85 POSIX_GUARD(s2n_hash_digest(digest, digest_out, digest_length));
86
87 struct s2n_blob digest_blob = { 0 };
88 POSIX_GUARD(s2n_blob_init(&digest_blob, digest_out, digest_length));
89 POSIX_GUARD(s2n_rsa_pkcs1v15_sign_digest(priv, digest->alg, &digest_blob, signature));
90
91 return S2N_SUCCESS;
92 }
93
s2n_rsa_pkcs1v15_verify(const struct s2n_pkey * pub,struct s2n_hash_state * digest,struct s2n_blob * signature)94 int s2n_rsa_pkcs1v15_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature)
95 {
96 uint8_t digest_length;
97 int digest_NID_type;
98 POSIX_GUARD(s2n_hash_digest_size(digest->alg, &digest_length));
99 POSIX_GUARD(s2n_hash_NID_type(digest->alg, &digest_NID_type));
100 POSIX_ENSURE_LTE(digest_length, S2N_MAX_DIGEST_LEN);
101
102 const s2n_rsa_public_key *key = &pub->key.rsa_key;
103
104 uint8_t digest_out[S2N_MAX_DIGEST_LEN];
105 POSIX_GUARD(s2n_hash_digest(digest, digest_out, digest_length));
106
107 POSIX_GUARD_OSSL(RSA_verify(digest_NID_type, digest_out, digest_length, signature->data, signature->size, key->rsa), S2N_ERR_VERIFY_SIGNATURE);
108
109 return 0;
110 }
111
112 /* this function returns whether RSA PSS signing is supported */
s2n_is_rsa_pss_signing_supported()113 int s2n_is_rsa_pss_signing_supported()
114 {
115 return RSA_PSS_SIGNING_SUPPORTED;
116 }
117
118 #if RSA_PSS_SIGNING_SUPPORTED
119
s2n_hash_alg_to_evp_alg(s2n_hash_algorithm alg)120 const EVP_MD* s2n_hash_alg_to_evp_alg(s2n_hash_algorithm alg)
121 {
122 switch (alg) {
123 case S2N_HASH_MD5_SHA1:
124 return EVP_md5_sha1();
125 case S2N_HASH_SHA1:
126 return EVP_sha1();
127 case S2N_HASH_SHA224:
128 return EVP_sha224();
129 case S2N_HASH_SHA256:
130 return EVP_sha256();
131 case S2N_HASH_SHA384:
132 return EVP_sha384();
133 case S2N_HASH_SHA512:
134 return EVP_sha512();
135 default:
136 return NULL;
137 }
138 }
139
140 /* On some versions of OpenSSL, "EVP_PKEY_CTX_set_signature_md()" is just a macro that casts digest_alg to "void*",
141 * which fails to compile when the "-Werror=cast-qual" compiler flag is enabled. So we work around this OpenSSL
142 * issue by turning off this compiler check for this one function with a cast through. */
s2n_evp_pkey_ctx_set_rsa_signature_digest(EVP_PKEY_CTX * ctx,const EVP_MD * digest_alg)143 static int s2n_evp_pkey_ctx_set_rsa_signature_digest(EVP_PKEY_CTX *ctx, const EVP_MD* digest_alg)
144 {
145 POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_signature_md(ctx,(EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM);
146 POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, (EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM);
147 return 0;
148 }
149
s2n_evp_pkey_ctx_free(EVP_PKEY_CTX ** ctx)150 static void s2n_evp_pkey_ctx_free(EVP_PKEY_CTX **ctx)
151 {
152 EVP_PKEY_CTX_free(*ctx);
153 }
154
s2n_rsa_pss_sign_digest(const struct s2n_pkey * priv,s2n_hash_algorithm hash_alg,struct s2n_blob * digest_in,struct s2n_blob * signature_out)155 int s2n_rsa_pss_sign_digest(const struct s2n_pkey *priv, s2n_hash_algorithm hash_alg,
156 struct s2n_blob *digest_in, struct s2n_blob *signature_out)
157 {
158 POSIX_ENSURE_REF(priv);
159 POSIX_ENSURE_REF(digest_in);
160 POSIX_ENSURE_REF(signature_out);
161
162 const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(hash_alg);
163 POSIX_ENSURE_REF(digest_alg);
164
165 /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_sign.html */
166 DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(priv->pkey, NULL), s2n_evp_pkey_ctx_free);
167 POSIX_ENSURE_REF(ctx);
168
169 size_t signature_len = signature_out->size;
170 POSIX_GUARD_OSSL(EVP_PKEY_sign_init(ctx), S2N_ERR_SIGN);
171 POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN);
172 POSIX_GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg));
173 POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST), S2N_ERR_SIGN);
174
175 /* Calling EVP_PKEY_sign() with NULL will only update the signature_len parameter so users can validate sizes. */
176 POSIX_GUARD_OSSL(EVP_PKEY_sign(ctx, NULL, &signature_len, digest_in->data, digest_in->size), S2N_ERR_SIGN);
177 POSIX_ENSURE(signature_len <= signature_out->size, S2N_ERR_SIZE_MISMATCH);
178
179 /* Actually sign the digest */
180 POSIX_GUARD_OSSL(EVP_PKEY_sign(ctx, signature_out->data, &signature_len, digest_in->data, digest_in->size), S2N_ERR_SIGN);
181 signature_out->size = signature_len;
182
183 return S2N_SUCCESS;
184 }
185
s2n_rsa_pss_sign(const struct s2n_pkey * priv,struct s2n_hash_state * digest,struct s2n_blob * signature_out)186 int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out)
187 {
188 POSIX_ENSURE_REF(digest);
189
190 uint8_t digest_length = 0;
191 uint8_t digest_data[S2N_MAX_DIGEST_LEN] = { 0 };
192 POSIX_GUARD(s2n_hash_digest_size(digest->alg, &digest_length));
193 POSIX_GUARD(s2n_hash_digest(digest, digest_data, digest_length));
194
195 struct s2n_blob digest_blob = { 0 };
196 POSIX_GUARD(s2n_blob_init(&digest_blob, digest_data, digest_length));
197 POSIX_GUARD(s2n_rsa_pss_sign_digest(priv, digest->alg, &digest_blob, signature_out));
198
199 return S2N_SUCCESS;
200 }
201
s2n_rsa_pss_verify(const struct s2n_pkey * pub,struct s2n_hash_state * digest,struct s2n_blob * signature_in)202 int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in)
203 {
204 POSIX_ENSURE_REF(pub);
205
206 uint8_t digest_length;
207 uint8_t digest_data[S2N_MAX_DIGEST_LEN];
208 POSIX_GUARD(s2n_hash_digest_size(digest->alg, &digest_length));
209 POSIX_GUARD(s2n_hash_digest(digest, digest_data, digest_length));
210 const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(digest->alg);
211 POSIX_ENSURE_REF(digest_alg);
212
213 /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_verify.html */
214 DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pub->pkey, NULL), s2n_evp_pkey_ctx_free);
215 POSIX_ENSURE_REF(ctx);
216
217 POSIX_GUARD_OSSL(EVP_PKEY_verify_init(ctx), S2N_ERR_VERIFY_SIGNATURE);
218 POSIX_GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN);
219 POSIX_GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg));
220 POSIX_GUARD_OSSL(EVP_PKEY_verify(ctx, signature_in->data, signature_in->size, digest_data, digest_length), S2N_ERR_VERIFY_SIGNATURE);
221
222 return 0;
223 }
224
225 #else
226
s2n_rsa_pss_sign_digest(const struct s2n_pkey * priv,s2n_hash_algorithm hash_alg,struct s2n_blob * digest_in,struct s2n_blob * signature_out)227 int s2n_rsa_pss_sign_digest(const struct s2n_pkey *priv, s2n_hash_algorithm hash_alg,
228 struct s2n_blob *digest_in, struct s2n_blob *signature_out)
229 {
230 POSIX_BAIL(S2N_RSA_PSS_NOT_SUPPORTED);
231 }
232
s2n_rsa_pss_sign(const struct s2n_pkey * priv,struct s2n_hash_state * digest,struct s2n_blob * signature_out)233 int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out)
234 {
235 POSIX_BAIL(S2N_RSA_PSS_NOT_SUPPORTED);
236 }
237
s2n_rsa_pss_verify(const struct s2n_pkey * pub,struct s2n_hash_state * digest,struct s2n_blob * signature_in)238 int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in)
239 {
240 POSIX_BAIL(S2N_RSA_PSS_NOT_SUPPORTED);
241 }
242
243 #endif
244