1 /* $OpenBSD: cms_pwri.c,v 1.29 2023/07/08 08:26:26 beck 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_local.h" 66 #include "asn1/asn1_local.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 LCRYPTO_ALIAS(CMS_RecipientInfo_set0_password); 88 89 CMS_RecipientInfo * 90 CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid, 91 int pbe_nid, unsigned char *pass, ssize_t passlen, 92 const EVP_CIPHER *kekciph) 93 { 94 CMS_RecipientInfo *ri = NULL; 95 CMS_EnvelopedData *env; 96 CMS_PasswordRecipientInfo *pwri; 97 EVP_CIPHER_CTX *ctx = NULL; 98 X509_ALGOR *encalg = NULL; 99 unsigned char iv[EVP_MAX_IV_LENGTH]; 100 int ivlen; 101 102 env = cms_get0_enveloped(cms); 103 if (!env) 104 return NULL; 105 106 if (wrap_nid <= 0) 107 wrap_nid = NID_id_alg_PWRI_KEK; 108 109 if (pbe_nid <= 0) 110 pbe_nid = NID_id_pbkdf2; 111 112 /* Get from enveloped data */ 113 if (kekciph == NULL) 114 kekciph = env->encryptedContentInfo->cipher; 115 116 if (kekciph == NULL) { 117 CMSerror(CMS_R_NO_CIPHER); 118 return NULL; 119 } 120 if (wrap_nid != NID_id_alg_PWRI_KEK) { 121 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 122 return NULL; 123 } 124 125 /* Setup algorithm identifier for cipher */ 126 encalg = X509_ALGOR_new(); 127 if (encalg == NULL) { 128 goto merr; 129 } 130 131 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) 132 goto merr; 133 134 if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) { 135 CMSerror(ERR_R_EVP_LIB); 136 goto err; 137 } 138 139 ivlen = EVP_CIPHER_CTX_iv_length(ctx); 140 141 if (ivlen > 0) { 142 arc4random_buf(iv, ivlen); 143 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) { 144 CMSerror(ERR_R_EVP_LIB); 145 goto err; 146 } 147 encalg->parameter = ASN1_TYPE_new(); 148 if (!encalg->parameter) { 149 CMSerror(ERR_R_MALLOC_FAILURE); 150 goto err; 151 } 152 if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) { 153 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 154 goto err; 155 } 156 } 157 158 encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); 159 160 EVP_CIPHER_CTX_free(ctx); 161 ctx = NULL; 162 163 /* Initialize recipient info */ 164 ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it); 165 if (ri == NULL) 166 goto merr; 167 168 ri->d.pwri = (CMS_PasswordRecipientInfo *)ASN1_item_new(&CMS_PasswordRecipientInfo_it); 169 if (ri->d.pwri == NULL) 170 goto merr; 171 ri->type = CMS_RECIPINFO_PASS; 172 173 pwri = ri->d.pwri; 174 /* Since this is overwritten, free up empty structure already there */ 175 X509_ALGOR_free(pwri->keyEncryptionAlgorithm); 176 pwri->keyEncryptionAlgorithm = X509_ALGOR_new(); 177 if (pwri->keyEncryptionAlgorithm == NULL) 178 goto merr; 179 pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid); 180 pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new(); 181 if (pwri->keyEncryptionAlgorithm->parameter == NULL) 182 goto merr; 183 184 if (!ASN1_item_pack(encalg, &X509_ALGOR_it, 185 &pwri->keyEncryptionAlgorithm->parameter->value.sequence)) 186 goto merr; 187 pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE; 188 189 X509_ALGOR_free(encalg); 190 encalg = NULL; 191 192 /* Setup PBE algorithm */ 193 194 pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1); 195 196 if (!pwri->keyDerivationAlgorithm) 197 goto err; 198 199 CMS_RecipientInfo_set0_password(ri, pass, passlen); 200 pwri->version = 0; 201 202 if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri)) 203 goto merr; 204 205 return ri; 206 207 merr: 208 CMSerror(ERR_R_MALLOC_FAILURE); 209 err: 210 EVP_CIPHER_CTX_free(ctx); 211 if (ri) 212 ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it); 213 X509_ALGOR_free(encalg); 214 215 return NULL; 216 } 217 LCRYPTO_ALIAS(CMS_add0_recipient_password); 218 219 /* 220 * This is an implementation of the key wrapping mechanism in RFC3211, at 221 * some point this should go into EVP. 222 */ 223 224 static int 225 kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 226 size_t inlen, EVP_CIPHER_CTX *ctx) 227 { 228 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 229 unsigned char *tmp; 230 int outl, rv = 0; 231 232 if (inlen < 2 * blocklen) { 233 /* too small */ 234 return 0; 235 } 236 if (inlen % blocklen) { 237 /* Invalid size */ 238 return 0; 239 } 240 if ((tmp = malloc(inlen)) == NULL) { 241 CMSerror(ERR_R_MALLOC_FAILURE); 242 return 0; 243 } 244 245 /* setup IV by decrypting last two blocks */ 246 if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, 247 in + inlen - 2 * blocklen, blocklen * 2) 248 /* 249 * Do a decrypt of last decrypted block to set IV to correct value 250 * output it to start of buffer so we don't corrupt decrypted block 251 * this works because buffer is at least two block lengths long. 252 */ 253 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen) 254 /* Can now decrypt first n - 1 blocks */ 255 || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) 256 257 /* Reset IV to original value */ 258 || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) 259 /* Decrypt again */ 260 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) 261 goto err; 262 /* Check check bytes */ 263 if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { 264 /* Check byte failure */ 265 goto err; 266 } 267 if (inlen < (size_t)(tmp[0] - 4)) { 268 /* Invalid length value */ 269 goto err; 270 } 271 *outlen = (size_t)tmp[0]; 272 memcpy(out, tmp + 4, *outlen); 273 rv = 1; 274 275 err: 276 freezero(tmp, inlen); 277 278 return rv; 279 } 280 281 static int 282 kek_wrap_key(unsigned char *out, size_t *outlen, const unsigned char *in, 283 size_t inlen, EVP_CIPHER_CTX *ctx) 284 { 285 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx); 286 size_t olen; 287 int dummy; 288 289 /* 290 * First decide length of output buffer: need header and round up to 291 * multiple of block length. 292 */ 293 olen = (inlen + 4 + blocklen - 1) / blocklen; 294 olen *= blocklen; 295 if (olen < 2 * blocklen) { 296 /* Key too small */ 297 return 0; 298 } 299 if (inlen > 0xFF) { 300 /* Key too large */ 301 return 0; 302 } 303 if (out) { 304 /* Set header */ 305 out[0] = (unsigned char)inlen; 306 out[1] = in[0] ^ 0xFF; 307 out[2] = in[1] ^ 0xFF; 308 out[3] = in[2] ^ 0xFF; 309 memcpy(out + 4, in, inlen); 310 /* Add random padding to end */ 311 if (olen > inlen + 4) 312 arc4random_buf(out + 4 + inlen, olen - 4 - inlen); 313 /* Encrypt twice */ 314 if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) || 315 !EVP_EncryptUpdate(ctx, out, &dummy, out, olen)) 316 return 0; 317 } 318 319 *outlen = olen; 320 321 return 1; 322 } 323 324 /* Encrypt/Decrypt content key in PWRI recipient info */ 325 326 int 327 cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, 328 int en_de) 329 { 330 CMS_EncryptedContentInfo *ec; 331 CMS_PasswordRecipientInfo *pwri; 332 int r = 0; 333 X509_ALGOR *algtmp, *kekalg = NULL; 334 EVP_CIPHER_CTX *kekctx = NULL; 335 const EVP_CIPHER *kekcipher; 336 unsigned char *key = NULL; 337 size_t keylen; 338 339 ec = cms->d.envelopedData->encryptedContentInfo; 340 341 pwri = ri->d.pwri; 342 343 if (!pwri->pass) { 344 CMSerror(CMS_R_NO_PASSWORD); 345 return 0; 346 } 347 algtmp = pwri->keyEncryptionAlgorithm; 348 349 if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { 350 CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); 351 return 0; 352 } 353 354 if (algtmp->parameter != NULL && 355 algtmp->parameter->type == V_ASN1_SEQUENCE && 356 algtmp->parameter->value.sequence != NULL) 357 kekalg = ASN1_item_unpack(algtmp->parameter->value.sequence, 358 &X509_ALGOR_it); 359 360 if (kekalg == NULL) { 361 CMSerror(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); 362 return 0; 363 } 364 365 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); 366 if (!kekcipher) { 367 CMSerror(CMS_R_UNKNOWN_CIPHER); 368 return 0; 369 } 370 371 kekctx = EVP_CIPHER_CTX_new(); 372 if (kekctx == NULL) { 373 CMSerror(ERR_R_MALLOC_FAILURE); 374 return 0; 375 } 376 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ 377 if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) 378 goto err; 379 EVP_CIPHER_CTX_set_padding(kekctx, 0); 380 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { 381 CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); 382 goto err; 383 } 384 385 algtmp = pwri->keyDerivationAlgorithm; 386 387 /* Finish password based key derivation to setup key in "ctx" */ 388 389 if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass, 390 pwri->passlen, algtmp->parameter, kekctx, en_de) < 0) { 391 CMSerror(ERR_R_EVP_LIB); 392 goto err; 393 } 394 395 /* Finally wrap/unwrap the key */ 396 397 if (en_de) { 398 if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx)) 399 goto err; 400 401 key = malloc(keylen); 402 if (key == NULL) 403 goto err; 404 405 if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx)) 406 goto err; 407 pwri->encryptedKey->data = key; 408 pwri->encryptedKey->length = keylen; 409 } else { 410 key = malloc(pwri->encryptedKey->length); 411 if (key == NULL) { 412 CMSerror(ERR_R_MALLOC_FAILURE); 413 goto err; 414 } 415 if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data, 416 pwri->encryptedKey->length, kekctx)) { 417 CMSerror(CMS_R_UNWRAP_FAILURE); 418 goto err; 419 } 420 421 freezero(ec->key, ec->keylen); 422 ec->key = key; 423 ec->keylen = keylen; 424 } 425 426 r = 1; 427 428 err: 429 EVP_CIPHER_CTX_free(kekctx); 430 if (!r) 431 free(key); 432 X509_ALGOR_free(kekalg); 433 434 return r; 435 } 436