1 /* $OpenBSD: cms_pwri.c,v 1.27 2022/01/19 13:47:44 inoguchi Exp $ */ 2 /* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4 * project. 5 */ 6 /* ==================================================================== 7 * Copyright (c) 2009 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 */ 54 55 #include <string.h> 56 57 #include "cryptlib.h" 58 #include <openssl/asn1t.h> 59 #include <openssl/pem.h> 60 #include <openssl/x509v3.h> 61 #include <openssl/err.h> 62 #include <openssl/cms.h> 63 #include <openssl/rand.h> 64 #include <openssl/aes.h> 65 #include "cms_lcl.h" 66 #include "asn1/asn1_locl.h" 67 68 int 69 CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, unsigned char *pass, 70 ssize_t passlen) 71 { 72 CMS_PasswordRecipientInfo *pwri; 73 74 if (ri->type != CMS_RECIPINFO_PASS) { 75 CMSerror(CMS_R_NOT_PWRI); 76 return 0; 77 } 78 79 pwri = ri->d.pwri; 80 pwri->pass = pass; 81 if (pass && passlen < 0) 82 passlen = strlen((char *)pass); 83 pwri->passlen = passlen; 84 85 return 1; 86 } 87 88 CMS_RecipientInfo * 89 CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid, 90 int pbe_nid, unsigned char *pass, ssize_t passlen, 91 const EVP_CIPHER *kekciph) 92 { 93 CMS_RecipientInfo *ri = NULL; 94 CMS_EnvelopedData *env; 95 CMS_PasswordRecipientInfo *pwri; 96 EVP_CIPHER_CTX *ctx = NULL; 97 X509_ALGOR *encalg = NULL; 98 unsigned char iv[EVP_MAX_IV_LENGTH]; 99 int ivlen; 100 101 env = cms_get0_enveloped(cms); 102 if (!env) 103 return NULL; 104 105 if (wrap_nid <= 0) 106 wrap_nid = NID_id_alg_PWRI_KEK; 107 108 if (pbe_nid <= 0) 109 pbe_nid = NID_id_pbkdf2; 110 111 /* Get from enveloped data */ 112 if (kekciph == NULL) 113 kekciph = env->encryptedContentInfo->cipher; 114 115 if (kekciph == NULL) { 116 CMSerror(CMS_R_NO_CIPHER); 117 return NULL; 118 } 119 if (wrap_nid != NID_id_alg_PWRI_KEK) { 120 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 121 return NULL; 122 } 123 124 /* Setup algorithm identifier for cipher */ 125 encalg = X509_ALGOR_new(); 126 if (encalg == NULL) { 127 goto merr; 128 } 129 130 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) 131 goto merr; 132 133 if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) { 134 CMSerror(ERR_R_EVP_LIB); 135 goto err; 136 } 137 138 ivlen = EVP_CIPHER_CTX_iv_length(ctx); 139 140 if (ivlen > 0) { 141 arc4random_buf(iv, ivlen); 142 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) { 143 CMSerror(ERR_R_EVP_LIB); 144 goto err; 145 } 146 encalg->parameter = ASN1_TYPE_new(); 147 if (!encalg->parameter) { 148 CMSerror(ERR_R_MALLOC_FAILURE); 149 goto err; 150 } 151 if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) { 152 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 153 goto err; 154 } 155 } 156 157 encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); 158 159 EVP_CIPHER_CTX_free(ctx); 160 ctx = NULL; 161 162 /* Initialize recipient info */ 163 ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it); 164 if (ri == NULL) 165 goto merr; 166 167 ri->d.pwri = (CMS_PasswordRecipientInfo *)ASN1_item_new(&CMS_PasswordRecipientInfo_it); 168 if (ri->d.pwri == NULL) 169 goto merr; 170 ri->type = CMS_RECIPINFO_PASS; 171 172 pwri = ri->d.pwri; 173 /* Since this is overwritten, free up empty structure already there */ 174 X509_ALGOR_free(pwri->keyEncryptionAlgorithm); 175 pwri->keyEncryptionAlgorithm = X509_ALGOR_new(); 176 if (pwri->keyEncryptionAlgorithm == NULL) 177 goto merr; 178 pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid); 179 pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new(); 180 if (pwri->keyEncryptionAlgorithm->parameter == NULL) 181 goto merr; 182 183 if (!ASN1_item_pack(encalg, &X509_ALGOR_it, 184 &pwri->keyEncryptionAlgorithm->parameter->value.sequence)) 185 goto merr; 186 pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE; 187 188 X509_ALGOR_free(encalg); 189 encalg = NULL; 190 191 /* Setup PBE algorithm */ 192 193 pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1); 194 195 if (!pwri->keyDerivationAlgorithm) 196 goto err; 197 198 CMS_RecipientInfo_set0_password(ri, pass, passlen); 199 pwri->version = 0; 200 201 if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) 202 goto merr; 203 204 return ri; 205 206 merr: 207 CMSerror(ERR_R_MALLOC_FAILURE); 208 err: 209 EVP_CIPHER_CTX_free(ctx); 210 if (ri) 211 ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it); 212 X509_ALGOR_free(encalg); 213 214 return NULL; 215 } 216 217 /* 218 * This is an implementation of the key wrapping mechanism in RFC3211, at 219 * some point this should go into EVP. 220 */ 221 222 static int 223 kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 224 size_t inlen, EVP_CIPHER_CTX *ctx) 225 { 226 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 227 unsigned char *tmp; 228 int outl, rv = 0; 229 230 if (inlen < 2 * blocklen) { 231 /* too small */ 232 return 0; 233 } 234 if (inlen % blocklen) { 235 /* Invalid size */ 236 return 0; 237 } 238 if ((tmp = malloc(inlen)) == NULL) { 239 CMSerror(ERR_R_MALLOC_FAILURE); 240 return 0; 241 } 242 243 /* setup IV by decrypting last two blocks */ 244 if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, 245 in + inlen - 2 * blocklen, blocklen * 2) 246 /* 247 * Do a decrypt of last decrypted block to set IV to correct value 248 * output it to start of buffer so we don't corrupt decrypted block 249 * this works because buffer is at least two block lengths long. 250 */ 251 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen) 252 /* Can now decrypt first n - 1 blocks */ 253 || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) 254 255 /* Reset IV to original value */ 256 || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) 257 /* Decrypt again */ 258 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) 259 goto err; 260 /* Check check bytes */ 261 if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { 262 /* Check byte failure */ 263 goto err; 264 } 265 if (inlen < (size_t)(tmp[0] - 4)) { 266 /* Invalid length value */ 267 goto err; 268 } 269 *outlen = (size_t)tmp[0]; 270 memcpy(out, tmp + 4, *outlen); 271 rv = 1; 272 273 err: 274 freezero(tmp, inlen); 275 276 return rv; 277 } 278 279 static int 280 kek_wrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 281 size_t inlen, EVP_CIPHER_CTX *ctx) 282 { 283 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 284 size_t olen; 285 int dummy; 286 287 /* 288 * First decide length of output buffer: need header and round up to 289 * multiple of block length. 290 */ 291 olen = (inlen + 4 + blocklen - 1) / blocklen; 292 olen *= blocklen; 293 if (olen < 2 * blocklen) { 294 /* Key too small */ 295 return 0; 296 } 297 if (inlen > 0xFF) { 298 /* Key too large */ 299 return 0; 300 } 301 if (out) { 302 /* Set header */ 303 out[0] = (unsigned char)inlen; 304 out[1] = in[0] ^ 0xFF; 305 out[2] = in[1] ^ 0xFF; 306 out[3] = in[2] ^ 0xFF; 307 memcpy(out + 4, in, inlen); 308 /* Add random padding to end */ 309 if (olen > inlen + 4) 310 arc4random_buf(out + 4 + inlen, olen - 4 - inlen); 311 /* Encrypt twice */ 312 if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) || 313 !EVP_EncryptUpdate(ctx, out, &dummy, out, olen)) 314 return 0; 315 } 316 317 *outlen = olen; 318 319 return 1; 320 } 321 322 /* Encrypt/Decrypt content key in PWRI recipient info */ 323 324 int 325 cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, 326 int en_de) 327 { 328 CMS_EncryptedContentInfo *ec; 329 CMS_PasswordRecipientInfo *pwri; 330 int r = 0; 331 X509_ALGOR *algtmp, *kekalg = NULL; 332 EVP_CIPHER_CTX *kekctx = NULL; 333 const EVP_CIPHER *kekcipher; 334 unsigned char *key = NULL; 335 size_t keylen; 336 337 ec = cms->d.envelopedData->encryptedContentInfo; 338 339 pwri = ri->d.pwri; 340 341 if (!pwri->pass) { 342 CMSerror(CMS_R_NO_PASSWORD); 343 return 0; 344 } 345 algtmp = pwri->keyEncryptionAlgorithm; 346 347 if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { 348 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 349 return 0; 350 } 351 352 if (algtmp->parameter != NULL && 353 algtmp->parameter->type == V_ASN1_SEQUENCE && 354 algtmp->parameter->value.sequence != NULL) 355 kekalg = ASN1_item_unpack(algtmp->parameter->value.sequence, 356 &X509_ALGOR_it); 357 358 if (kekalg == NULL) { 359 CMSerror(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); 360 return 0; 361 } 362 363 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); 364 if (!kekcipher) { 365 CMSerror(CMS_R_UNKNOWN_CIPHER); 366 return 0; 367 } 368 369 kekctx = EVP_CIPHER_CTX_new(); 370 if (kekctx == NULL) { 371 CMSerror(ERR_R_MALLOC_FAILURE); 372 return 0; 373 } 374 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ 375 if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) 376 goto err; 377 EVP_CIPHER_CTX_set_padding(kekctx, 0); 378 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { 379 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 380 goto err; 381 } 382 383 algtmp = pwri->keyDerivationAlgorithm; 384 385 /* Finish password based key derivation to setup key in "ctx" */ 386 387 if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass, 388 pwri->passlen, algtmp->parameter, kekctx, en_de) < 0) { 389 CMSerror(ERR_R_EVP_LIB); 390 goto err; 391 } 392 393 /* Finally wrap/unwrap the key */ 394 395 if (en_de) { 396 if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx)) 397 goto err; 398 399 key = malloc(keylen); 400 if (key == NULL) 401 goto err; 402 403 if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx)) 404 goto err; 405 pwri->encryptedKey->data = key; 406 pwri->encryptedKey->length = keylen; 407 } else { 408 key = malloc(pwri->encryptedKey->length); 409 if (key == NULL) { 410 CMSerror(ERR_R_MALLOC_FAILURE); 411 goto err; 412 } 413 if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, 414 pwri->encryptedKey->length, kekctx)) { 415 CMSerror(CMS_R_UNWRAP_FAILURE); 416 goto err; 417 } 418 419 freezero(ec->key, ec->keylen); 420 ec->key = key; 421 ec->keylen = keylen; 422 } 423 424 r = 1; 425 426 err: 427 EVP_CIPHER_CTX_free(kekctx); 428 if (!r) 429 free(key); 430 X509_ALGOR_free(kekalg); 431 432 return r; 433 } 434