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