mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
	
	
		
			164 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
		
		
			
		
	
	
			164 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
|  | /*
 | ||
|  |  * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. | ||
|  |  * | ||
|  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | ||
|  |  * this file except in compliance with the License.  You can obtain a copy | ||
|  |  * in the file LICENSE in the source distribution or at | ||
|  |  * https://www.openssl.org/source/license.html
 | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <assert.h>
 | ||
|  | #include <limits.h>
 | ||
|  | #include <openssl/cms.h>
 | ||
|  | #include <openssl/core_names.h>
 | ||
|  | #include <openssl/err.h>
 | ||
|  | #include <openssl/decoder.h>
 | ||
|  | #include "internal/sizes.h"
 | ||
|  | #include "crypto/asn1.h"
 | ||
|  | #include "crypto/evp.h"
 | ||
|  | #include "cms_local.h"
 | ||
|  | 
 | ||
|  | static int kem_cms_decrypt(CMS_RecipientInfo *ri) | ||
|  | { | ||
|  |     uint32_t *kekLength; | ||
|  |     X509_ALGOR *wrap; | ||
|  |     EVP_PKEY_CTX *pctx; | ||
|  |     EVP_CIPHER_CTX *kekctx; | ||
|  |     uint32_t cipher_length; | ||
|  |     char name[OSSL_MAX_NAME_SIZE]; | ||
|  |     EVP_CIPHER *kekcipher = NULL; | ||
|  |     int rv = 0; | ||
|  | 
 | ||
|  |     if (!ossl_cms_RecipientInfo_kemri_get0_alg(ri, &kekLength, &wrap)) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); | ||
|  |     if (pctx == NULL) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     kekctx = CMS_RecipientInfo_kemri_get0_ctx(ri); | ||
|  |     if (kekctx == NULL) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     OBJ_obj2txt(name, sizeof(name), wrap->algorithm, 0); | ||
|  |     kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); | ||
|  |     if (kekcipher == NULL || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) | ||
|  |         goto err; | ||
|  |     if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) | ||
|  |         goto err; | ||
|  |     if (EVP_CIPHER_asn1_to_param(kekctx, wrap->parameter) <= 0) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     cipher_length = EVP_CIPHER_CTX_get_key_length(kekctx); | ||
|  |     if (cipher_length != *kekLength) { | ||
|  |         ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH); | ||
|  |         goto err; | ||
|  |     } | ||
|  | 
 | ||
|  |     rv = 1; | ||
|  | err: | ||
|  |     EVP_CIPHER_free(kekcipher); | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | static int kem_cms_encrypt(CMS_RecipientInfo *ri) | ||
|  | { | ||
|  |     uint32_t *kekLength; | ||
|  |     X509_ALGOR *wrap; | ||
|  |     X509_ALGOR *kdf; | ||
|  |     EVP_PKEY_CTX *pctx; | ||
|  |     EVP_PKEY *pkey; | ||
|  |     int security_bits; | ||
|  |     const ASN1_OBJECT *kdf_obj = NULL; | ||
|  |     unsigned char kemri_x509_algor[OSSL_MAX_ALGORITHM_ID_SIZE]; | ||
|  |     OSSL_PARAM params[2]; | ||
|  |     X509_ALGOR *x509_algor = NULL; | ||
|  |     EVP_CIPHER_CTX *kekctx; | ||
|  |     int wrap_nid; | ||
|  |     int rv = 0; | ||
|  | 
 | ||
|  |     if (!ossl_cms_RecipientInfo_kemri_get0_alg(ri, &kekLength, &wrap)) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     kdf = CMS_RecipientInfo_kemri_get0_kdf_alg(ri); | ||
|  |     if (kdf == NULL) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); | ||
|  |     if (pctx == NULL) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     pkey = EVP_PKEY_CTX_get0_pkey(pctx); | ||
|  |     if (pkey == NULL) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     security_bits = EVP_PKEY_get_security_bits(pkey); | ||
|  |     if (security_bits == 0) | ||
|  |         goto err; | ||
|  | 
 | ||
|  |     X509_ALGOR_get0(&kdf_obj, NULL, NULL, kdf); | ||
|  |     if (kdf_obj == NULL || OBJ_obj2nid(kdf_obj) == NID_undef) { | ||
|  |         /*
 | ||
|  |          * If the KDF OID hasn't already been set, then query the provider | ||
|  |          * for a default KDF. | ||
|  |          */ | ||
|  |         params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_CMS_KEMRI_KDF_ALGORITHM, | ||
|  |                                                       kemri_x509_algor, sizeof(kemri_x509_algor)); | ||
|  |         params[1] = OSSL_PARAM_construct_end(); | ||
|  |         if (!EVP_PKEY_get_params(pkey, params)) | ||
|  |             goto err; | ||
|  |         if (OSSL_PARAM_modified(¶ms[0])) { | ||
|  |             const unsigned char *p = kemri_x509_algor; | ||
|  | 
 | ||
|  |             x509_algor = d2i_X509_ALGOR(NULL, &p, (long)params[0].return_size); | ||
|  |             if (x509_algor == NULL) | ||
|  |                 goto err; | ||
|  |             if (!X509_ALGOR_copy(kdf, x509_algor)) | ||
|  |                 goto err; | ||
|  |         } else { | ||
|  |             if (!X509_ALGOR_set0(kdf, OBJ_nid2obj(NID_HKDF_SHA256), V_ASN1_UNDEF, NULL)) | ||
|  |                 return 0; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Get wrap NID */ | ||
|  |     kekctx = CMS_RecipientInfo_kemri_get0_ctx(ri); | ||
|  |     if (kekctx == NULL) | ||
|  |         goto err; | ||
|  |     *kekLength = EVP_CIPHER_CTX_get_key_length(kekctx); | ||
|  |     wrap_nid = EVP_CIPHER_CTX_get_type(kekctx); | ||
|  | 
 | ||
|  |     /* Package wrap algorithm in an AlgorithmIdentifier */ | ||
|  |     ASN1_OBJECT_free(wrap->algorithm); | ||
|  |     ASN1_TYPE_free(wrap->parameter); | ||
|  |     wrap->algorithm = OBJ_nid2obj(wrap_nid); | ||
|  |     wrap->parameter = ASN1_TYPE_new(); | ||
|  |     if (wrap->parameter == NULL) | ||
|  |         goto err; | ||
|  |     if (EVP_CIPHER_param_to_asn1(kekctx, wrap->parameter) <= 0) | ||
|  |         goto err; | ||
|  |     if (ASN1_TYPE_get(wrap->parameter) == NID_undef) { | ||
|  |         ASN1_TYPE_free(wrap->parameter); | ||
|  |         wrap->parameter = NULL; | ||
|  |     } | ||
|  | 
 | ||
|  |     rv = 1; | ||
|  | err: | ||
|  |     X509_ALGOR_free(x509_algor); | ||
|  |     return rv; | ||
|  | } | ||
|  | 
 | ||
|  | int ossl_cms_kem_envelope(CMS_RecipientInfo *ri, int decrypt) | ||
|  | { | ||
|  |     assert(decrypt == 0 || decrypt == 1); | ||
|  | 
 | ||
|  |     if (decrypt == 1) | ||
|  |         return kem_cms_decrypt(ri); | ||
|  | 
 | ||
|  |     if (decrypt == 0) | ||
|  |         return kem_cms_encrypt(ri); | ||
|  | 
 | ||
|  |     ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); | ||
|  |     return 0; | ||
|  | } |