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