/src/openssl31/crypto/crmf/crmf_pbm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * Copyright Nokia 2007-2019 |
4 | | * Copyright Siemens AG 2015-2019 |
5 | | * |
6 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
7 | | * this file except in compliance with the License. You can obtain a copy |
8 | | * in the file LICENSE in the source distribution or at |
9 | | * https://www.openssl.org/source/license.html |
10 | | * |
11 | | * CRMF implementation by Martin Peylo, Miikka Viljanen, and David von Oheimb. |
12 | | */ |
13 | | |
14 | | |
15 | | #include <string.h> |
16 | | |
17 | | #include <openssl/rand.h> |
18 | | #include <openssl/evp.h> |
19 | | #include <openssl/hmac.h> |
20 | | |
21 | | /* explicit #includes not strictly needed since implied by the above: */ |
22 | | #include <openssl/asn1t.h> |
23 | | #include <openssl/crmf.h> |
24 | | #include <openssl/err.h> |
25 | | #include <openssl/params.h> |
26 | | #include <openssl/core_names.h> |
27 | | |
28 | | #include "internal/sizes.h" |
29 | | |
30 | | #include "crmf_local.h" |
31 | | |
32 | | /*- |
33 | | * creates and initializes OSSL_CRMF_PBMPARAMETER (section 4.4) |
34 | | * |slen| SHOULD be at least 8 (16 is common) |
35 | | * |owfnid| e.g., NID_sha256 |
36 | | * |itercnt| MUST be >= 100 (e.g., 500) and <= OSSL_CRMF_PBM_MAX_ITERATION_COUNT |
37 | | * |macnid| e.g., NID_hmac_sha1 |
38 | | * returns pointer to OSSL_CRMF_PBMPARAMETER on success, NULL on error |
39 | | */ |
40 | | OSSL_CRMF_PBMPARAMETER *OSSL_CRMF_pbmp_new(OSSL_LIB_CTX *libctx, size_t slen, |
41 | | int owfnid, size_t itercnt, |
42 | | int macnid) |
43 | 0 | { |
44 | 0 | OSSL_CRMF_PBMPARAMETER *pbm = NULL; |
45 | 0 | unsigned char *salt = NULL; |
46 | |
|
47 | 0 | if ((pbm = OSSL_CRMF_PBMPARAMETER_new()) == NULL) |
48 | 0 | goto err; |
49 | | |
50 | | /* |
51 | | * salt contains a randomly generated value used in computing the key |
52 | | * of the MAC process. The salt SHOULD be at least 8 octets (64 |
53 | | * bits) long. |
54 | | */ |
55 | 0 | if ((salt = OPENSSL_malloc(slen)) == NULL) |
56 | 0 | goto err; |
57 | 0 | if (RAND_bytes_ex(libctx, salt, slen, 0) <= 0) { |
58 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_FAILURE_OBTAINING_RANDOM); |
59 | 0 | goto err; |
60 | 0 | } |
61 | 0 | if (!ASN1_OCTET_STRING_set(pbm->salt, salt, (int)slen)) |
62 | 0 | goto err; |
63 | | |
64 | | /* |
65 | | * owf identifies the hash algorithm and associated parameters used to |
66 | | * compute the key used in the MAC process. All implementations MUST |
67 | | * support SHA-1. |
68 | | */ |
69 | 0 | if (!X509_ALGOR_set0(pbm->owf, OBJ_nid2obj(owfnid), V_ASN1_UNDEF, NULL)) { |
70 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_SETTING_OWF_ALGOR_FAILURE); |
71 | 0 | goto err; |
72 | 0 | } |
73 | | |
74 | | /* |
75 | | * iterationCount identifies the number of times the hash is applied |
76 | | * during the key computation process. The iterationCount MUST be a |
77 | | * minimum of 100. Many people suggest using values as high as 1000 |
78 | | * iterations as the minimum value. The trade off here is between |
79 | | * protection of the password from attacks and the time spent by the |
80 | | * server processing all of the different iterations in deriving |
81 | | * passwords. Hashing is generally considered a cheap operation but |
82 | | * this may not be true with all hash functions in the future. |
83 | | */ |
84 | 0 | if (itercnt < 100) { |
85 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_ITERATIONCOUNT_BELOW_100); |
86 | 0 | goto err; |
87 | 0 | } |
88 | 0 | if (itercnt > OSSL_CRMF_PBM_MAX_ITERATION_COUNT) { |
89 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT); |
90 | 0 | goto err; |
91 | 0 | } |
92 | | |
93 | 0 | if (!ASN1_INTEGER_set(pbm->iterationCount, itercnt)) { |
94 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_CRMFERROR); |
95 | 0 | goto err; |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * mac identifies the algorithm and associated parameters of the MAC |
100 | | * function to be used. All implementations MUST support HMAC-SHA1 [HMAC]. |
101 | | * All implementations SHOULD support DES-MAC and Triple-DES-MAC [PKCS11]. |
102 | | */ |
103 | 0 | if (!X509_ALGOR_set0(pbm->mac, OBJ_nid2obj(macnid), V_ASN1_UNDEF, NULL)) { |
104 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_SETTING_MAC_ALGOR_FAILURE); |
105 | 0 | goto err; |
106 | 0 | } |
107 | | |
108 | 0 | OPENSSL_free(salt); |
109 | 0 | return pbm; |
110 | 0 | err: |
111 | 0 | OPENSSL_free(salt); |
112 | 0 | OSSL_CRMF_PBMPARAMETER_free(pbm); |
113 | 0 | return NULL; |
114 | 0 | } |
115 | | |
116 | | /*- |
117 | | * calculates the PBM based on the settings of the given OSSL_CRMF_PBMPARAMETER |
118 | | * |pbmp| identifies the algorithms, salt to use |
119 | | * |msg| message to apply the PBM for |
120 | | * |msglen| length of the message |
121 | | * |sec| key to use |
122 | | * |seclen| length of the key |
123 | | * |out| pointer to the computed mac, will be set on success |
124 | | * |outlen| if not NULL, will set variable to the length of the mac on success |
125 | | * returns 1 on success, 0 on error |
126 | | */ |
127 | | int OSSL_CRMF_pbm_new(OSSL_LIB_CTX *libctx, const char *propq, |
128 | | const OSSL_CRMF_PBMPARAMETER *pbmp, |
129 | | const unsigned char *msg, size_t msglen, |
130 | | const unsigned char *sec, size_t seclen, |
131 | | unsigned char **out, size_t *outlen) |
132 | 745 | { |
133 | 745 | int mac_nid, hmac_md_nid = NID_undef; |
134 | 745 | char mdname[OSSL_MAX_NAME_SIZE]; |
135 | 745 | char hmac_mdname[OSSL_MAX_NAME_SIZE]; |
136 | 745 | EVP_MD *owf = NULL; |
137 | 745 | EVP_MD_CTX *ctx = NULL; |
138 | 745 | unsigned char basekey[EVP_MAX_MD_SIZE]; |
139 | 745 | unsigned int bklen = EVP_MAX_MD_SIZE; |
140 | 745 | int64_t iterations; |
141 | 745 | unsigned char *mac_res = 0; |
142 | 745 | int ok = 0; |
143 | | |
144 | 745 | if (out == NULL || pbmp == NULL || pbmp->mac == NULL |
145 | 745 | || pbmp->mac->algorithm == NULL || msg == NULL || sec == NULL) { |
146 | 0 | ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); |
147 | 0 | goto err; |
148 | 0 | } |
149 | 745 | if ((mac_res = OPENSSL_malloc(EVP_MAX_MD_SIZE)) == NULL) |
150 | 0 | goto err; |
151 | | |
152 | | /* |
153 | | * owf identifies the hash algorithm and associated parameters used to |
154 | | * compute the key used in the MAC process. All implementations MUST |
155 | | * support SHA-1. |
156 | | */ |
157 | 745 | OBJ_obj2txt(mdname, sizeof(mdname), pbmp->owf->algorithm, 0); |
158 | 745 | if ((owf = EVP_MD_fetch(libctx, mdname, propq)) == NULL) { |
159 | 49 | ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM); |
160 | 49 | goto err; |
161 | 49 | } |
162 | | |
163 | 696 | if ((ctx = EVP_MD_CTX_new()) == NULL) |
164 | 0 | goto err; |
165 | | |
166 | | /* compute the basekey of the salted secret */ |
167 | 696 | if (!EVP_DigestInit_ex(ctx, owf, NULL)) |
168 | 0 | goto err; |
169 | | /* first the secret */ |
170 | 696 | if (!EVP_DigestUpdate(ctx, sec, seclen)) |
171 | 0 | goto err; |
172 | | /* then the salt */ |
173 | 696 | if (!EVP_DigestUpdate(ctx, pbmp->salt->data, pbmp->salt->length)) |
174 | 0 | goto err; |
175 | 696 | if (!EVP_DigestFinal_ex(ctx, basekey, &bklen)) |
176 | 3 | goto err; |
177 | 693 | if (!ASN1_INTEGER_get_int64(&iterations, pbmp->iterationCount) |
178 | 693 | || iterations < 100 /* min from RFC */ |
179 | 693 | || iterations > OSSL_CRMF_PBM_MAX_ITERATION_COUNT) { |
180 | 208 | ERR_raise(ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT); |
181 | 208 | goto err; |
182 | 208 | } |
183 | | |
184 | | /* the first iteration was already done above */ |
185 | 2.55M | while (--iterations > 0) { |
186 | 2.55M | if (!EVP_DigestInit_ex(ctx, owf, NULL)) |
187 | 0 | goto err; |
188 | 2.55M | if (!EVP_DigestUpdate(ctx, basekey, bklen)) |
189 | 0 | goto err; |
190 | 2.55M | if (!EVP_DigestFinal_ex(ctx, basekey, &bklen)) |
191 | 0 | goto err; |
192 | 2.55M | } |
193 | | |
194 | | /* |
195 | | * mac identifies the algorithm and associated parameters of the MAC |
196 | | * function to be used. All implementations MUST support HMAC-SHA1 [HMAC]. |
197 | | * All implementations SHOULD support DES-MAC and Triple-DES-MAC [PKCS11]. |
198 | | */ |
199 | 485 | mac_nid = OBJ_obj2nid(pbmp->mac->algorithm); |
200 | | |
201 | 485 | if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, mac_nid, NULL, &hmac_md_nid, NULL) |
202 | 485 | || OBJ_obj2txt(hmac_mdname, sizeof(hmac_mdname), |
203 | 257 | OBJ_nid2obj(hmac_md_nid), 0) <= 0) { |
204 | 228 | ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM); |
205 | 228 | goto err; |
206 | 228 | } |
207 | 257 | if (EVP_Q_mac(libctx, "HMAC", propq, hmac_mdname, NULL, basekey, bklen, |
208 | 257 | msg, msglen, mac_res, EVP_MAX_MD_SIZE, outlen) == NULL) |
209 | 11 | goto err; |
210 | | |
211 | 246 | ok = 1; |
212 | | |
213 | 745 | err: |
214 | 745 | OPENSSL_cleanse(basekey, bklen); |
215 | 745 | EVP_MD_free(owf); |
216 | 745 | EVP_MD_CTX_free(ctx); |
217 | | |
218 | 745 | if (ok == 1) { |
219 | 246 | *out = mac_res; |
220 | 246 | return 1; |
221 | 246 | } |
222 | | |
223 | 499 | OPENSSL_free(mac_res); |
224 | | |
225 | 499 | if (pbmp != NULL && pbmp->mac != NULL) { |
226 | 499 | char buf[128]; |
227 | | |
228 | 499 | if (OBJ_obj2txt(buf, sizeof(buf), pbmp->mac->algorithm, 0)) |
229 | 499 | ERR_add_error_data(1, buf); |
230 | 499 | } |
231 | 499 | return 0; |
232 | 745 | } |