diff options
Diffstat (limited to 'crypto/crmf')
-rw-r--r-- | crypto/crmf/build.info | 2 | ||||
-rw-r--r-- | crypto/crmf/crmf_asn.c | 235 | ||||
-rw-r--r-- | crypto/crmf/crmf_err.c | 74 | ||||
-rw-r--r-- | crypto/crmf/crmf_lib.c | 715 | ||||
-rw-r--r-- | crypto/crmf/crmf_local.h | 385 | ||||
-rw-r--r-- | crypto/crmf/crmf_pbm.c | 233 |
6 files changed, 1644 insertions, 0 deletions
diff --git a/crypto/crmf/build.info b/crypto/crmf/build.info new file mode 100644 index 000000000000..7cfa8ec2b076 --- /dev/null +++ b/crypto/crmf/build.info @@ -0,0 +1,2 @@ +LIBS=../../libcrypto +SOURCE[../../libcrypto]=crmf_asn.c crmf_err.c crmf_lib.c crmf_pbm.c diff --git a/crypto/crmf/crmf_asn.c b/crypto/crmf/crmf_asn.c new file mode 100644 index 000000000000..3354b89736e9 --- /dev/null +++ b/crypto/crmf/crmf_asn.c @@ -0,0 +1,235 @@ +/*- + * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2019 + * Copyright Siemens AG 2015-2019 + * + * 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 + * + * CRMF implementation by Martin Peylo, Miikka Viljanen, and David von Oheimb. + */ + +#include <openssl/asn1t.h> + +#include "crmf_local.h" + +/* explicit #includes not strictly needed since implied by the above: */ +#include <openssl/crmf.h> + +ASN1_SEQUENCE(OSSL_CRMF_PRIVATEKEYINFO) = { + ASN1_SIMPLE(OSSL_CRMF_PRIVATEKEYINFO, version, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_CRMF_PRIVATEKEYINFO, privateKeyAlgorithm, X509_ALGOR), + ASN1_SIMPLE(OSSL_CRMF_PRIVATEKEYINFO, privateKey, ASN1_OCTET_STRING), + ASN1_IMP_SET_OF_OPT(OSSL_CRMF_PRIVATEKEYINFO, attributes, X509_ATTRIBUTE, 0) +} ASN1_SEQUENCE_END(OSSL_CRMF_PRIVATEKEYINFO) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_PRIVATEKEYINFO) + + +ASN1_CHOICE(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER) = { + ASN1_SIMPLE(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER, value.string, ASN1_UTF8STRING), + ASN1_SIMPLE(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER, value.generalName, GENERAL_NAME) +} ASN1_CHOICE_END(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER) + + +ASN1_SEQUENCE(OSSL_CRMF_ENCKEYWITHID) = { + ASN1_SIMPLE(OSSL_CRMF_ENCKEYWITHID, privateKey, OSSL_CRMF_PRIVATEKEYINFO), + ASN1_OPT(OSSL_CRMF_ENCKEYWITHID, identifier, + OSSL_CRMF_ENCKEYWITHID_IDENTIFIER) +} ASN1_SEQUENCE_END(OSSL_CRMF_ENCKEYWITHID) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ENCKEYWITHID) + + +ASN1_SEQUENCE(OSSL_CRMF_CERTID) = { + ASN1_SIMPLE(OSSL_CRMF_CERTID, issuer, GENERAL_NAME), + ASN1_SIMPLE(OSSL_CRMF_CERTID, serialNumber, ASN1_INTEGER) +} ASN1_SEQUENCE_END(OSSL_CRMF_CERTID) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_CERTID) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID) + + +ASN1_SEQUENCE(OSSL_CRMF_ENCRYPTEDVALUE) = { + ASN1_IMP_OPT(OSSL_CRMF_ENCRYPTEDVALUE, intendedAlg, X509_ALGOR, 0), + ASN1_IMP_OPT(OSSL_CRMF_ENCRYPTEDVALUE, symmAlg, X509_ALGOR, 1), + ASN1_IMP_OPT(OSSL_CRMF_ENCRYPTEDVALUE, encSymmKey, ASN1_BIT_STRING, 2), + ASN1_IMP_OPT(OSSL_CRMF_ENCRYPTEDVALUE, keyAlg, X509_ALGOR, 3), + ASN1_IMP_OPT(OSSL_CRMF_ENCRYPTEDVALUE, valueHint, ASN1_OCTET_STRING, 4), + ASN1_SIMPLE(OSSL_CRMF_ENCRYPTEDVALUE, encValue, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(OSSL_CRMF_ENCRYPTEDVALUE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDVALUE) + +ASN1_SEQUENCE(OSSL_CRMF_SINGLEPUBINFO) = { + ASN1_SIMPLE(OSSL_CRMF_SINGLEPUBINFO, pubMethod, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_CRMF_SINGLEPUBINFO, pubLocation, GENERAL_NAME) +} ASN1_SEQUENCE_END(OSSL_CRMF_SINGLEPUBINFO) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_SINGLEPUBINFO) + + +ASN1_SEQUENCE(OSSL_CRMF_PKIPUBLICATIONINFO) = { + ASN1_SIMPLE(OSSL_CRMF_PKIPUBLICATIONINFO, action, ASN1_INTEGER), + ASN1_SEQUENCE_OF_OPT(OSSL_CRMF_PKIPUBLICATIONINFO, pubInfos, + OSSL_CRMF_SINGLEPUBINFO) +} ASN1_SEQUENCE_END(OSSL_CRMF_PKIPUBLICATIONINFO) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_PKIPUBLICATIONINFO) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_PKIPUBLICATIONINFO) + + +ASN1_SEQUENCE(OSSL_CRMF_PKMACVALUE) = { + ASN1_SIMPLE(OSSL_CRMF_PKMACVALUE, algId, X509_ALGOR), + ASN1_SIMPLE(OSSL_CRMF_PKMACVALUE, value, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(OSSL_CRMF_PKMACVALUE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_PKMACVALUE) + + +ASN1_CHOICE(OSSL_CRMF_POPOPRIVKEY) = { + ASN1_IMP(OSSL_CRMF_POPOPRIVKEY, value.thisMessage, ASN1_BIT_STRING, 0), + ASN1_IMP(OSSL_CRMF_POPOPRIVKEY, value.subsequentMessage, ASN1_INTEGER, 1), + ASN1_IMP(OSSL_CRMF_POPOPRIVKEY, value.dhMAC, ASN1_BIT_STRING, 2), + ASN1_IMP(OSSL_CRMF_POPOPRIVKEY, value.agreeMAC, OSSL_CRMF_PKMACVALUE, 3), + ASN1_IMP(OSSL_CRMF_POPOPRIVKEY, value.encryptedKey, ASN1_NULL, 4), +} ASN1_CHOICE_END(OSSL_CRMF_POPOPRIVKEY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_POPOPRIVKEY) + + +ASN1_SEQUENCE(OSSL_CRMF_PBMPARAMETER) = { + ASN1_SIMPLE(OSSL_CRMF_PBMPARAMETER, salt, ASN1_OCTET_STRING), + ASN1_SIMPLE(OSSL_CRMF_PBMPARAMETER, owf, X509_ALGOR), + ASN1_SIMPLE(OSSL_CRMF_PBMPARAMETER, iterationCount, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_CRMF_PBMPARAMETER, mac, X509_ALGOR) +} ASN1_SEQUENCE_END(OSSL_CRMF_PBMPARAMETER) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_PBMPARAMETER) + + +ASN1_CHOICE(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO) = { + ASN1_EXP(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO, value.sender, + GENERAL_NAME, 0), + ASN1_SIMPLE(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO, value.publicKeyMAC, + OSSL_CRMF_PKMACVALUE) +} ASN1_CHOICE_END(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO) + + +ASN1_SEQUENCE(OSSL_CRMF_POPOSIGNINGKEYINPUT) = { + ASN1_SIMPLE(OSSL_CRMF_POPOSIGNINGKEYINPUT, authInfo, + OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO), + ASN1_SIMPLE(OSSL_CRMF_POPOSIGNINGKEYINPUT, publicKey, X509_PUBKEY) +} ASN1_SEQUENCE_END(OSSL_CRMF_POPOSIGNINGKEYINPUT) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEYINPUT) + + +ASN1_SEQUENCE(OSSL_CRMF_POPOSIGNINGKEY) = { + ASN1_IMP_OPT(OSSL_CRMF_POPOSIGNINGKEY, poposkInput, + OSSL_CRMF_POPOSIGNINGKEYINPUT, 0), + ASN1_SIMPLE(OSSL_CRMF_POPOSIGNINGKEY, algorithmIdentifier, X509_ALGOR), + ASN1_SIMPLE(OSSL_CRMF_POPOSIGNINGKEY, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(OSSL_CRMF_POPOSIGNINGKEY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEY) + + +ASN1_CHOICE(OSSL_CRMF_POPO) = { + ASN1_IMP(OSSL_CRMF_POPO, value.raVerified, ASN1_NULL, 0), + ASN1_IMP(OSSL_CRMF_POPO, value.signature, OSSL_CRMF_POPOSIGNINGKEY, 1), + ASN1_EXP(OSSL_CRMF_POPO, value.keyEncipherment, OSSL_CRMF_POPOPRIVKEY, 2), + ASN1_EXP(OSSL_CRMF_POPO, value.keyAgreement, OSSL_CRMF_POPOPRIVKEY, 3) +} ASN1_CHOICE_END(OSSL_CRMF_POPO) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_POPO) + + +ASN1_ADB_TEMPLATE(attributetypeandvalue_default) = + ASN1_OPT(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, value.other, ASN1_ANY); +ASN1_ADB(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) = { + ADB_ENTRY(NID_id_regCtrl_regToken, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.regToken, ASN1_UTF8STRING)), + ADB_ENTRY(NID_id_regCtrl_authenticator, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.authenticator, ASN1_UTF8STRING)), + ADB_ENTRY(NID_id_regCtrl_pkiPublicationInfo, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.pkiPublicationInfo, + OSSL_CRMF_PKIPUBLICATIONINFO)), + ADB_ENTRY(NID_id_regCtrl_oldCertID, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.oldCertID, OSSL_CRMF_CERTID)), + ADB_ENTRY(NID_id_regCtrl_protocolEncrKey, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.protocolEncrKey, X509_PUBKEY)), + ADB_ENTRY(NID_id_regInfo_utf8Pairs, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.utf8Pairs, ASN1_UTF8STRING)), + ADB_ENTRY(NID_id_regInfo_certReq, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.certReq, OSSL_CRMF_CERTREQUEST)), +} ASN1_ADB_END(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, 0, type, 0, + &attributetypeandvalue_default_tt, NULL); + + +ASN1_SEQUENCE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) = { + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, type, ASN1_OBJECT), + ASN1_ADB_OBJECT(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +} ASN1_SEQUENCE_END(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) + +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) + + +ASN1_SEQUENCE(OSSL_CRMF_OPTIONALVALIDITY) = { + ASN1_EXP_OPT(OSSL_CRMF_OPTIONALVALIDITY, notBefore, ASN1_TIME, 0), + ASN1_EXP_OPT(OSSL_CRMF_OPTIONALVALIDITY, notAfter, ASN1_TIME, 1) +} ASN1_SEQUENCE_END(OSSL_CRMF_OPTIONALVALIDITY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_OPTIONALVALIDITY) + + +ASN1_SEQUENCE(OSSL_CRMF_CERTTEMPLATE) = { + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, version, ASN1_INTEGER, 0), + /* + * serialNumber MUST be omitted. This field is assigned by the CA + * during certificate creation. + */ + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, serialNumber, ASN1_INTEGER, 1), + /* + * signingAlg MUST be omitted. This field is assigned by the CA + * during certificate creation. + */ + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, signingAlg, X509_ALGOR, 2), + ASN1_EXP_OPT(OSSL_CRMF_CERTTEMPLATE, issuer, X509_NAME, 3), + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, validity, + OSSL_CRMF_OPTIONALVALIDITY, 4), + ASN1_EXP_OPT(OSSL_CRMF_CERTTEMPLATE, subject, X509_NAME, 5), + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, publicKey, X509_PUBKEY, 6), + /* issuerUID is deprecated in version 2 */ + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, issuerUID, ASN1_BIT_STRING, 7), + /* subjectUID is deprecated in version 2 */ + ASN1_IMP_OPT(OSSL_CRMF_CERTTEMPLATE, subjectUID, ASN1_BIT_STRING, 8), + ASN1_IMP_SEQUENCE_OF_OPT(OSSL_CRMF_CERTTEMPLATE, extensions, + X509_EXTENSION, 9), +} ASN1_SEQUENCE_END(OSSL_CRMF_CERTTEMPLATE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE) + + +ASN1_SEQUENCE(OSSL_CRMF_CERTREQUEST) = { + ASN1_SIMPLE(OSSL_CRMF_CERTREQUEST, certReqId, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_CRMF_CERTREQUEST, certTemplate, OSSL_CRMF_CERTTEMPLATE), + ASN1_SEQUENCE_OF_OPT(OSSL_CRMF_CERTREQUEST, controls, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +} ASN1_SEQUENCE_END(OSSL_CRMF_CERTREQUEST) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_CERTREQUEST) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTREQUEST) + + +ASN1_SEQUENCE(OSSL_CRMF_MSG) = { + ASN1_SIMPLE(OSSL_CRMF_MSG, certReq, OSSL_CRMF_CERTREQUEST), + ASN1_OPT(OSSL_CRMF_MSG, popo, OSSL_CRMF_POPO), + ASN1_SEQUENCE_OF_OPT(OSSL_CRMF_MSG, regInfo, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +} ASN1_SEQUENCE_END(OSSL_CRMF_MSG) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_MSG) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_MSG) + +ASN1_ITEM_TEMPLATE(OSSL_CRMF_MSGS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, + OSSL_CRMF_MSGS, OSSL_CRMF_MSG) +ASN1_ITEM_TEMPLATE_END(OSSL_CRMF_MSGS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_MSGS) diff --git a/crypto/crmf/crmf_err.c b/crypto/crmf/crmf_err.c new file mode 100644 index 000000000000..44b2f2757d2c --- /dev/null +++ b/crypto/crmf/crmf_err.c @@ -0,0 +1,74 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2021 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 <openssl/err.h> +#include <openssl/crmferr.h> +#include "crypto/crmferr.h" + +#ifndef OPENSSL_NO_CRMF + +# ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA CRMF_str_reasons[] = { + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_BAD_PBM_ITERATIONCOUNT), + "bad pbm iterationcount"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_CRMFERROR), "crmferror"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR), "error"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECODING_CERTIFICATE), + "error decoding certificate"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_CERTIFICATE), + "error decrypting certificate"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY), + "error decrypting symmetric key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_FAILURE_OBTAINING_RANDOM), + "failure obtaining random"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ITERATIONCOUNT_BELOW_100), + "iterationcount below 100"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_MALFORMED_IV), "malformed iv"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_NULL_ARGUMENT), "null argument"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPOSKINPUT_NOT_SUPPORTED), + "poposkinput not supported"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY), + "popo inconsistent public key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING), "popo missing"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_PUBLIC_KEY), + "popo missing public key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_SUBJECT), + "popo missing subject"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED), + "popo raverified not accepted"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_MAC_ALGOR_FAILURE), + "setting mac algor failure"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_OWF_ALGOR_FAILURE), + "setting owf algor failure"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_ALGORITHM), + "unsupported algorithm"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_CIPHER), + "unsupported cipher"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO), + "unsupported method for creating popo"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_POPO_METHOD), + "unsupported popo method"}, + {0, NULL} +}; + +# endif + +int ossl_err_load_CRMF_strings(void) +{ +# ifndef OPENSSL_NO_ERR + if (ERR_reason_error_string(CRMF_str_reasons[0].error) == NULL) + ERR_load_strings_const(CRMF_str_reasons); +# endif + return 1; +} +#else +NON_EMPTY_TRANSLATION_UNIT +#endif diff --git a/crypto/crmf/crmf_lib.c b/crypto/crmf/crmf_lib.c new file mode 100644 index 000000000000..3607fb0bf417 --- /dev/null +++ b/crypto/crmf/crmf_lib.c @@ -0,0 +1,715 @@ +/*- + * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2018 + * Copyright Siemens AG 2015-2019 + * + * 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 + * + * CRMF implementation by Martin Peylo, Miikka Viljanen, and David von Oheimb. + */ + +/* + * This file contains the functions that handle the individual items inside + * the CRMF structures + */ + +/* + * NAMING + * + * The 0 functions use the supplied structure pointer directly in the parent and + * it will be freed up when the parent is freed. + * + * The 1 functions use a copy of the supplied structure pointer (or in some + * cases increases its link count) in the parent and so both should be freed up. + */ + +#include <openssl/asn1t.h> + +#include "crmf_local.h" +#include "internal/constant_time.h" +#include "internal/sizes.h" + +/* explicit #includes not strictly needed since implied by the above: */ +#include <openssl/crmf.h> +#include <openssl/err.h> +#include <openssl/evp.h> + +/*- + * atyp = Attribute Type + * valt = Value Type + * ctrlinf = "regCtrl" or "regInfo" + */ +#define IMPLEMENT_CRMF_CTRL_FUNC(atyp, valt, ctrlinf) \ +valt *OSSL_CRMF_MSG_get0_##ctrlinf##_##atyp(const OSSL_CRMF_MSG *msg) \ +{ \ + int i; \ + STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) *controls; \ + OSSL_CRMF_ATTRIBUTETYPEANDVALUE *atav = NULL; \ + \ + if (msg == NULL || msg->certReq == NULL) \ + return NULL; \ + controls = msg->certReq->controls; \ + for (i = 0; i < sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_num(controls); i++) { \ + atav = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_value(controls, i); \ + if (OBJ_obj2nid(atav->type) == NID_id_##ctrlinf##_##atyp) \ + return atav->value.atyp; \ + } \ + return NULL; \ +} \ + \ +int OSSL_CRMF_MSG_set1_##ctrlinf##_##atyp(OSSL_CRMF_MSG *msg, const valt *in) \ +{ \ + OSSL_CRMF_ATTRIBUTETYPEANDVALUE *atav = NULL; \ + \ + if (msg == NULL || in == NULL) \ + goto err; \ + if ((atav = OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new()) == NULL) \ + goto err; \ + if ((atav->type = OBJ_nid2obj(NID_id_##ctrlinf##_##atyp)) == NULL) \ + goto err; \ + if ((atav->value.atyp = valt##_dup(in)) == NULL) \ + goto err; \ + if (!OSSL_CRMF_MSG_push0_##ctrlinf(msg, atav)) \ + goto err; \ + return 1; \ + err: \ + OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(atav); \ + return 0; \ +} + + +/*- + * Pushes the given control attribute into the controls stack of a CertRequest + * (section 6) + * returns 1 on success, 0 on error + */ +static int OSSL_CRMF_MSG_push0_regCtrl(OSSL_CRMF_MSG *crm, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE *ctrl) +{ + int new = 0; + + if (crm == NULL || crm->certReq == NULL || ctrl == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (crm->certReq->controls == NULL) { + crm->certReq->controls = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_null(); + if (crm->certReq->controls == NULL) + goto err; + new = 1; + } + if (!sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push(crm->certReq->controls, ctrl)) + goto err; + + return 1; + err: + if (new != 0) { + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(crm->certReq->controls); + crm->certReq->controls = NULL; + } + return 0; +} + +/* id-regCtrl-regToken Control (section 6.1) */ +IMPLEMENT_CRMF_CTRL_FUNC(regToken, ASN1_STRING, regCtrl) + +/* id-regCtrl-authenticator Control (section 6.2) */ +#define ASN1_UTF8STRING_dup ASN1_STRING_dup +IMPLEMENT_CRMF_CTRL_FUNC(authenticator, ASN1_UTF8STRING, regCtrl) + +int OSSL_CRMF_MSG_set0_SinglePubInfo(OSSL_CRMF_SINGLEPUBINFO *spi, + int method, GENERAL_NAME *nm) +{ + if (spi == NULL + || method < OSSL_CRMF_PUB_METHOD_DONTCARE + || method > OSSL_CRMF_PUB_METHOD_LDAP) { + ERR_raise(ERR_LIB_CRMF, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + if (!ASN1_INTEGER_set(spi->pubMethod, method)) + return 0; + GENERAL_NAME_free(spi->pubLocation); + spi->pubLocation = nm; + return 1; +} + +int +OSSL_CRMF_MSG_PKIPublicationInfo_push0_SinglePubInfo(OSSL_CRMF_PKIPUBLICATIONINFO *pi, + OSSL_CRMF_SINGLEPUBINFO *spi) +{ + if (pi == NULL || spi == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + if (pi->pubInfos == NULL) + pi->pubInfos = sk_OSSL_CRMF_SINGLEPUBINFO_new_null(); + if (pi->pubInfos == NULL) + return 0; + + return sk_OSSL_CRMF_SINGLEPUBINFO_push(pi->pubInfos, spi); +} + +int OSSL_CRMF_MSG_set_PKIPublicationInfo_action(OSSL_CRMF_PKIPUBLICATIONINFO *pi, + int action) +{ + if (pi == NULL + || action < OSSL_CRMF_PUB_ACTION_DONTPUBLISH + || action > OSSL_CRMF_PUB_ACTION_PLEASEPUBLISH) { + ERR_raise(ERR_LIB_CRMF, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + return ASN1_INTEGER_set(pi->action, action); +} + +/* id-regCtrl-pkiPublicationInfo Control (section 6.3) */ +IMPLEMENT_CRMF_CTRL_FUNC(pkiPublicationInfo, OSSL_CRMF_PKIPUBLICATIONINFO, + regCtrl) + +/* id-regCtrl-oldCertID Control (section 6.5) from the given */ +IMPLEMENT_CRMF_CTRL_FUNC(oldCertID, OSSL_CRMF_CERTID, regCtrl) + +OSSL_CRMF_CERTID *OSSL_CRMF_CERTID_gen(const X509_NAME *issuer, + const ASN1_INTEGER *serial) +{ + OSSL_CRMF_CERTID *cid = NULL; + + if (issuer == NULL || serial == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + + if ((cid = OSSL_CRMF_CERTID_new()) == NULL) + goto err; + + if (!X509_NAME_set(&cid->issuer->d.directoryName, issuer)) + goto err; + cid->issuer->type = GEN_DIRNAME; + + ASN1_INTEGER_free(cid->serialNumber); + if ((cid->serialNumber = ASN1_INTEGER_dup(serial)) == NULL) + goto err; + + return cid; + + err: + OSSL_CRMF_CERTID_free(cid); + return NULL; +} + +/* + * id-regCtrl-protocolEncrKey Control (section 6.6) + */ +IMPLEMENT_CRMF_CTRL_FUNC(protocolEncrKey, X509_PUBKEY, regCtrl) + +/*- + * Pushes the attribute given in regInfo in to the CertReqMsg->regInfo stack. + * (section 7) + * returns 1 on success, 0 on error + */ +static int OSSL_CRMF_MSG_push0_regInfo(OSSL_CRMF_MSG *crm, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE *ri) +{ + STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) *info = NULL; + + if (crm == NULL || ri == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (crm->regInfo == NULL) + crm->regInfo = info = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_null(); + if (crm->regInfo == NULL) + goto err; + if (!sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push(crm->regInfo, ri)) + goto err; + return 1; + + err: + if (info != NULL) + crm->regInfo = NULL; + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(info); + return 0; +} + +/* id-regInfo-utf8Pairs to regInfo (section 7.1) */ +IMPLEMENT_CRMF_CTRL_FUNC(utf8Pairs, ASN1_UTF8STRING, regInfo) + +/* id-regInfo-certReq to regInfo (section 7.2) */ +IMPLEMENT_CRMF_CTRL_FUNC(certReq, OSSL_CRMF_CERTREQUEST, regInfo) + + +/* retrieves the certificate template of crm */ +OSSL_CRMF_CERTTEMPLATE *OSSL_CRMF_MSG_get0_tmpl(const OSSL_CRMF_MSG *crm) +{ + if (crm == NULL || crm->certReq == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + return crm->certReq->certTemplate; +} + + +int OSSL_CRMF_MSG_set0_validity(OSSL_CRMF_MSG *crm, + ASN1_TIME *notBefore, ASN1_TIME *notAfter) +{ + OSSL_CRMF_OPTIONALVALIDITY *vld; + OSSL_CRMF_CERTTEMPLATE *tmpl = OSSL_CRMF_MSG_get0_tmpl(crm); + + if (tmpl == NULL) { /* also crm == NULL implies this */ + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if ((vld = OSSL_CRMF_OPTIONALVALIDITY_new()) == NULL) + return 0; + vld->notBefore = notBefore; + vld->notAfter = notAfter; + tmpl->validity = vld; + return 1; +} + + +int OSSL_CRMF_MSG_set_certReqId(OSSL_CRMF_MSG *crm, int rid) +{ + if (crm == NULL || crm->certReq == NULL || crm->certReq->certReqId == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + return ASN1_INTEGER_set(crm->certReq->certReqId, rid); +} + +/* get ASN.1 encoded integer, return -1 on error */ +static int crmf_asn1_get_int(const ASN1_INTEGER *a) +{ + int64_t res; + + if (!ASN1_INTEGER_get_int64(&res, a)) { + ERR_raise(ERR_LIB_CRMF, ASN1_R_INVALID_NUMBER); + return -1; + } + if (res < INT_MIN) { + ERR_raise(ERR_LIB_CRMF, ASN1_R_TOO_SMALL); + return -1; + } + if (res > INT_MAX) { + ERR_raise(ERR_LIB_CRMF, ASN1_R_TOO_LARGE); + return -1; + } + return (int)res; +} + +int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm) +{ + if (crm == NULL || /* not really needed: */ crm->certReq == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return -1; + } + return crmf_asn1_get_int(crm->certReq->certReqId); +} + + +int OSSL_CRMF_MSG_set0_extensions(OSSL_CRMF_MSG *crm, + X509_EXTENSIONS *exts) +{ + OSSL_CRMF_CERTTEMPLATE *tmpl = OSSL_CRMF_MSG_get0_tmpl(crm); + + if (tmpl == NULL) { /* also crm == NULL implies this */ + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (sk_X509_EXTENSION_num(exts) == 0) { + sk_X509_EXTENSION_free(exts); + exts = NULL; /* do not include empty extensions list */ + } + + sk_X509_EXTENSION_pop_free(tmpl->extensions, X509_EXTENSION_free); + tmpl->extensions = exts; + return 1; +} + + +int OSSL_CRMF_MSG_push0_extension(OSSL_CRMF_MSG *crm, + X509_EXTENSION *ext) +{ + int new = 0; + OSSL_CRMF_CERTTEMPLATE *tmpl = OSSL_CRMF_MSG_get0_tmpl(crm); + + if (tmpl == NULL || ext == NULL) { /* also crm == NULL implies this */ + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (tmpl->extensions == NULL) { + if ((tmpl->extensions = sk_X509_EXTENSION_new_null()) == NULL) + goto err; + new = 1; + } + + if (!sk_X509_EXTENSION_push(tmpl->extensions, ext)) + goto err; + return 1; + err: + if (new != 0) { + sk_X509_EXTENSION_free(tmpl->extensions); + tmpl->extensions = NULL; + } + return 0; +} + +static int create_popo_signature(OSSL_CRMF_POPOSIGNINGKEY *ps, + const OSSL_CRMF_CERTREQUEST *cr, + EVP_PKEY *pkey, const EVP_MD *digest, + OSSL_LIB_CTX *libctx, const char *propq) +{ + char name[80] = ""; + + if (ps == NULL || cr == NULL || pkey == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + if (ps->poposkInput != NULL) { + /* We do not support cases 1+2 defined in RFC 4211, section 4.1 */ + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPOSKINPUT_NOT_SUPPORTED); + return 0; + } + + if (EVP_PKEY_get_default_digest_name(pkey, name, sizeof(name)) > 0 + && strcmp(name, "UNDEF") == 0) /* at least for Ed25519, Ed448 */ + digest = NULL; + + return ASN1_item_sign_ex(ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST), + ps->algorithmIdentifier, NULL, ps->signature, cr, + NULL, pkey, digest, libctx, propq); +} + + +int OSSL_CRMF_MSG_create_popo(int meth, OSSL_CRMF_MSG *crm, + EVP_PKEY *pkey, const EVP_MD *digest, + OSSL_LIB_CTX *libctx, const char *propq) +{ + OSSL_CRMF_POPO *pp = NULL; + ASN1_INTEGER *tag = NULL; + + if (crm == NULL || (meth == OSSL_CRMF_POPO_SIGNATURE && pkey == NULL)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (meth == OSSL_CRMF_POPO_NONE) + goto end; + if ((pp = OSSL_CRMF_POPO_new()) == NULL) + goto err; + pp->type = meth; + + switch (meth) { + case OSSL_CRMF_POPO_RAVERIFIED: + if ((pp->value.raVerified = ASN1_NULL_new()) == NULL) + goto err; + break; + + case OSSL_CRMF_POPO_SIGNATURE: + { + OSSL_CRMF_POPOSIGNINGKEY *ps = OSSL_CRMF_POPOSIGNINGKEY_new(); + + if (ps == NULL) + goto err; + if (!create_popo_signature(ps, crm->certReq, pkey, digest, + libctx, propq)) { + OSSL_CRMF_POPOSIGNINGKEY_free(ps); + goto err; + } + pp->value.signature = ps; + } + break; + + case OSSL_CRMF_POPO_KEYENC: + if ((pp->value.keyEncipherment = OSSL_CRMF_POPOPRIVKEY_new()) == NULL) + goto err; + tag = ASN1_INTEGER_new(); + pp->value.keyEncipherment->type = + OSSL_CRMF_POPOPRIVKEY_SUBSEQUENTMESSAGE; + pp->value.keyEncipherment->value.subsequentMessage = tag; + if (tag == NULL + || !ASN1_INTEGER_set(tag, OSSL_CRMF_SUBSEQUENTMESSAGE_ENCRCERT)) + goto err; + break; + + default: + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO); + goto err; + } + + end: + OSSL_CRMF_POPO_free(crm->popo); + crm->popo = pp; + + return 1; + err: + OSSL_CRMF_POPO_free(pp); + return 0; +} + +/* verifies the Proof-of-Possession of the request with the given rid in reqs */ +int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs, + int rid, int acceptRAVerified, + OSSL_LIB_CTX *libctx, const char *propq) +{ + OSSL_CRMF_MSG *req = NULL; + X509_PUBKEY *pubkey = NULL; + OSSL_CRMF_POPOSIGNINGKEY *sig = NULL; + const ASN1_ITEM *it; + void *asn; + + if (reqs == NULL || (req = sk_OSSL_CRMF_MSG_value(reqs, rid)) == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + + if (req->popo == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_MISSING); + return 0; + } + + switch (req->popo->type) { + case OSSL_CRMF_POPO_RAVERIFIED: + if (!acceptRAVerified) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED); + return 0; + } + break; + case OSSL_CRMF_POPO_SIGNATURE: + pubkey = req->certReq->certTemplate->publicKey; + if (pubkey == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_MISSING_PUBLIC_KEY); + return 0; + } + sig = req->popo->value.signature; + if (sig->poposkInput != NULL) { + /* + * According to RFC 4211: publicKey contains a copy of + * the public key from the certificate template. This MUST be + * exactly the same value as contained in the certificate template. + */ + if (sig->poposkInput->publicKey == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_MISSING_PUBLIC_KEY); + return 0; + } + if (X509_PUBKEY_eq(pubkey, sig->poposkInput->publicKey) != 1) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY); + return 0; + } + it = ASN1_ITEM_rptr(OSSL_CRMF_POPOSIGNINGKEYINPUT); + asn = sig->poposkInput; + } else { + if (req->certReq->certTemplate->subject == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_POPO_MISSING_SUBJECT); + return 0; + } + it = ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST); + asn = req->certReq; + } + if (ASN1_item_verify_ex(it, sig->algorithmIdentifier, sig->signature, + asn, NULL, X509_PUBKEY_get0(pubkey), libctx, + propq) < 1) + return 0; + break; + case OSSL_CRMF_POPO_KEYENC: + case OSSL_CRMF_POPO_KEYAGREE: + default: + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_POPO_METHOD); + return 0; + } + return 1; +} + +/* retrieves the serialNumber of the given cert template or NULL on error */ +const ASN1_INTEGER +*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + return tmpl != NULL ? tmpl->serialNumber : NULL; +} + +const X509_NAME + *OSSL_CRMF_CERTTEMPLATE_get0_subject(const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + return tmpl != NULL ? tmpl->subject : NULL; +} + +/* retrieves the issuer name of the given cert template or NULL on error */ +const X509_NAME + *OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + return tmpl != NULL ? tmpl->issuer : NULL; +} + +X509_EXTENSIONS + *OSSL_CRMF_CERTTEMPLATE_get0_extensions(const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + return tmpl != NULL ? tmpl->extensions : NULL; +} + +/* retrieves the issuer name of the given CertId or NULL on error */ +const X509_NAME *OSSL_CRMF_CERTID_get0_issuer(const OSSL_CRMF_CERTID *cid) +{ + return cid != NULL && cid->issuer->type == GEN_DIRNAME ? + cid->issuer->d.directoryName : NULL; +} + +/* retrieves the serialNumber of the given CertId or NULL on error */ +const ASN1_INTEGER *OSSL_CRMF_CERTID_get0_serialNumber(const OSSL_CRMF_CERTID *cid) +{ + return cid != NULL ? cid->serialNumber : NULL; +} + +/*- + * fill in certificate template. + * Any value argument that is NULL will leave the respective field unchanged. + */ +int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl, + EVP_PKEY *pubkey, + const X509_NAME *subject, + const X509_NAME *issuer, + const ASN1_INTEGER *serial) +{ + if (tmpl == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return 0; + } + if (subject != NULL && !X509_NAME_set((X509_NAME **)&tmpl->subject, subject)) + return 0; + if (issuer != NULL && !X509_NAME_set((X509_NAME **)&tmpl->issuer, issuer)) + return 0; + if (serial != NULL) { + ASN1_INTEGER_free(tmpl->serialNumber); + if ((tmpl->serialNumber = ASN1_INTEGER_dup(serial)) == NULL) + return 0; + } + if (pubkey != NULL && !X509_PUBKEY_set(&tmpl->publicKey, pubkey)) + return 0; + return 1; +} + + +/*- + * Decrypts the certificate in the given encryptedValue using private key pkey. + * This is needed for the indirect PoP method as in RFC 4210 section 5.2.8.2. + * + * returns a pointer to the decrypted certificate + * returns NULL on error or if no certificate available + */ +X509 +*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, + OSSL_LIB_CTX *libctx, const char *propq, + EVP_PKEY *pkey) +{ + X509 *cert = NULL; /* decrypted certificate */ + EVP_CIPHER_CTX *evp_ctx = NULL; /* context for symmetric encryption */ + unsigned char *ek = NULL; /* decrypted symmetric encryption key */ + size_t eksize = 0; /* size of decrypted symmetric encryption key */ + EVP_CIPHER *cipher = NULL; /* used cipher */ + int cikeysize = 0; /* key size from cipher */ + unsigned char *iv = NULL; /* initial vector for symmetric encryption */ + unsigned char *outbuf = NULL; /* decryption output buffer */ + const unsigned char *p = NULL; /* needed for decoding ASN1 */ + int n, outlen = 0; + EVP_PKEY_CTX *pkctx = NULL; /* private key context */ + char name[OSSL_MAX_NAME_SIZE]; + + if (ecert == NULL || ecert->symmAlg == NULL || ecert->encSymmKey == NULL + || ecert->encValue == NULL || pkey == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + + /* select symmetric cipher based on algorithm given in message */ + OBJ_obj2txt(name, sizeof(name), ecert->symmAlg->algorithm, 0); + + (void)ERR_set_mark(); + cipher = EVP_CIPHER_fetch(NULL, name, NULL); + + if (cipher == NULL) + cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name); + + if (cipher == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER); + goto end; + } + (void)ERR_pop_to_mark(); + + cikeysize = EVP_CIPHER_get_key_length(cipher); + /* first the symmetric key needs to be decrypted */ + pkctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); + if (pkctx != NULL && EVP_PKEY_decrypt_init(pkctx) > 0) { + ASN1_BIT_STRING *encKey = ecert->encSymmKey; + size_t failure; + int retval; + + if (EVP_PKEY_decrypt(pkctx, NULL, &eksize, + encKey->data, encKey->length) <= 0 + || (ek = OPENSSL_malloc(eksize)) == NULL) + goto end; + retval = EVP_PKEY_decrypt(pkctx, ek, &eksize, + encKey->data, encKey->length); + ERR_clear_error(); /* error state may have sensitive information */ + failure = ~constant_time_is_zero_s(constant_time_msb(retval) + | constant_time_is_zero(retval)); + failure |= ~constant_time_eq_s(eksize, (size_t)cikeysize); + if (failure) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY); + goto end; + } + } else { + goto end; + } + if ((iv = OPENSSL_malloc(EVP_CIPHER_get_iv_length(cipher))) == NULL) + goto end; + if (ASN1_TYPE_get_octetstring(ecert->symmAlg->parameter, iv, + EVP_CIPHER_get_iv_length(cipher)) + != EVP_CIPHER_get_iv_length(cipher)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_MALFORMED_IV); + goto end; + } + + /* + * d2i_X509 changes the given pointer, so use p for decoding the message and + * keep the original pointer in outbuf so the memory can be freed later + */ + if ((p = outbuf = OPENSSL_malloc(ecert->encValue->length + + EVP_CIPHER_get_block_size(cipher))) == NULL + || (evp_ctx = EVP_CIPHER_CTX_new()) == NULL) + goto end; + EVP_CIPHER_CTX_set_padding(evp_ctx, 0); + + if (!EVP_DecryptInit(evp_ctx, cipher, ek, iv) + || !EVP_DecryptUpdate(evp_ctx, outbuf, &outlen, + ecert->encValue->data, + ecert->encValue->length) + || !EVP_DecryptFinal(evp_ctx, outbuf + outlen, &n)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_CERTIFICATE); + goto end; + } + outlen += n; + + /* convert decrypted certificate from DER to internal ASN.1 structure */ + if ((cert = X509_new_ex(libctx, propq)) == NULL) + goto end; + if (d2i_X509(&cert, &p, outlen) == NULL) + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE); + end: + EVP_PKEY_CTX_free(pkctx); + OPENSSL_free(outbuf); + EVP_CIPHER_CTX_free(evp_ctx); + EVP_CIPHER_free(cipher); + OPENSSL_clear_free(ek, eksize); + OPENSSL_free(iv); + return cert; +} diff --git a/crypto/crmf/crmf_local.h b/crypto/crmf/crmf_local.h new file mode 100644 index 000000000000..3b8c3701b54d --- /dev/null +++ b/crypto/crmf/crmf_local.h @@ -0,0 +1,385 @@ +/*- + * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2019 + * Copyright Siemens AG 2015-2019 + * + * 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 + * + * CRMF implementation by Martin Peylo, Miikka Viljanen, and David von Oheimb. + */ + +#ifndef OSSL_CRYPTO_CRMF_LOCAL_H +# define OSSL_CRYPTO_CRMF_LOCAL_H + +# include <openssl/crmf.h> +# include <openssl/err.h> + +/* explicit #includes not strictly needed since implied by the above: */ +# include <openssl/types.h> +# include <openssl/safestack.h> +# include <openssl/x509.h> +# include <openssl/x509v3.h> + +/*- + * EncryptedValue ::= SEQUENCE { + * intendedAlg [0] AlgorithmIdentifier OPTIONAL, + * -- the intended algorithm for which the value will be used + * symmAlg [1] AlgorithmIdentifier OPTIONAL, + * -- the symmetric algorithm used to encrypt the value + * encSymmKey [2] BIT STRING OPTIONAL, + * -- the (encrypted) symmetric key used to encrypt the value + * keyAlg [3] AlgorithmIdentifier OPTIONAL, + * -- algorithm used to encrypt the symmetric key + * valueHint [4] OCTET STRING OPTIONAL, + * -- a brief description or identifier of the encValue content + * -- (may be meaningful only to the sending entity, and + * -- used only if EncryptedValue might be re-examined + * -- by the sending entity in the future) + * encValue BIT STRING + * -- the encrypted value itself + * } + */ +struct ossl_crmf_encryptedvalue_st { + X509_ALGOR *intendedAlg; /* 0 */ + X509_ALGOR *symmAlg; /* 1 */ + ASN1_BIT_STRING *encSymmKey; /* 2 */ + X509_ALGOR *keyAlg; /* 3 */ + ASN1_OCTET_STRING *valueHint; /* 4 */ + ASN1_BIT_STRING *encValue; +} /* OSSL_CRMF_ENCRYPTEDVALUE */; + +/*- + * Attributes ::= SET OF Attribute + * => X509_ATTRIBUTE + * + * PrivateKeyInfo ::= SEQUENCE { + * version INTEGER, + * privateKeyAlgorithm AlgorithmIdentifier, + * privateKey OCTET STRING, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + */ +typedef struct ossl_crmf_privatekeyinfo_st { + ASN1_INTEGER *version; + X509_ALGOR *privateKeyAlgorithm; + ASN1_OCTET_STRING *privateKey; + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ +} OSSL_CRMF_PRIVATEKEYINFO; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PRIVATEKEYINFO) + +/*- + * section 4.2.1 Private Key Info Content Type + * id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21} + * + * EncKeyWithID ::= SEQUENCE { + * privateKey PrivateKeyInfo, + * identifier CHOICE { + * string UTF8String, + * generalName GeneralName + * } OPTIONAL + * } + */ +typedef struct ossl_crmf_enckeywithid_identifier_st { + int type; + union { + ASN1_UTF8STRING *string; + GENERAL_NAME *generalName; + } value; +} OSSL_CRMF_ENCKEYWITHID_IDENTIFIER; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ENCKEYWITHID_IDENTIFIER) + +typedef struct ossl_crmf_enckeywithid_st { + OSSL_CRMF_PRIVATEKEYINFO *privateKey; + /* [0] */ + OSSL_CRMF_ENCKEYWITHID_IDENTIFIER *identifier; +} OSSL_CRMF_ENCKEYWITHID; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ENCKEYWITHID) + +/*- + * CertId ::= SEQUENCE { + * issuer GeneralName, + * serialNumber INTEGER + * } + */ +struct ossl_crmf_certid_st { + GENERAL_NAME *issuer; + ASN1_INTEGER *serialNumber; +} /* OSSL_CRMF_CERTID */; + +/*- + * SinglePubInfo ::= SEQUENCE { + * pubMethod INTEGER { + * dontCare (0), + * x500 (1), + * web (2), + * ldap (3) }, + * pubLocation GeneralName OPTIONAL + * } + */ +struct ossl_crmf_singlepubinfo_st { + ASN1_INTEGER *pubMethod; + GENERAL_NAME *pubLocation; +} /* OSSL_CRMF_SINGLEPUBINFO */; +DEFINE_STACK_OF(OSSL_CRMF_SINGLEPUBINFO) +typedef STACK_OF(OSSL_CRMF_SINGLEPUBINFO) OSSL_CRMF_PUBINFOS; + + +/*- + * PKIPublicationInfo ::= SEQUENCE { + * action INTEGER { + * dontPublish (0), + * pleasePublish (1) }, + * pubInfos SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL + * -- pubInfos MUST NOT be present if action is "dontPublish" + * -- (if action is "pleasePublish" and pubInfos is omitted, + * -- "dontCare" is assumed) + * } + */ +struct ossl_crmf_pkipublicationinfo_st { + ASN1_INTEGER *action; + OSSL_CRMF_PUBINFOS *pubInfos; +} /* OSSL_CRMF_PKIPUBLICATIONINFO */; +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_PKIPUBLICATIONINFO) + +/*- + * PKMACValue ::= SEQUENCE { + * algId AlgorithmIdentifier, + * -- algorithm value shall be PasswordBasedMac {1 2 840 113533 7 66 13} + * -- parameter value is PBMParameter + * value BIT STRING + * } + */ +typedef struct ossl_crmf_pkmacvalue_st { + X509_ALGOR *algId; + ASN1_BIT_STRING *value; +} OSSL_CRMF_PKMACVALUE; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PKMACVALUE) + +/*- + * SubsequentMessage ::= INTEGER { + * encrCert (0), + * -- requests that resulting certificate be encrypted for the + * -- end entity (following which, POP will be proven in a + * -- confirmation message) + * challengeResp (1) + * -- requests that CA engage in challenge-response exchange with + * -- end entity in order to prove private key possession + * } + * + * POPOPrivKey ::= CHOICE { + * thisMessage [0] BIT STRING, -- Deprecated + * -- possession is proven in this message (which contains the private + * -- key itself (encrypted for the CA)) + * subsequentMessage [1] SubsequentMessage, + * -- possession will be proven in a subsequent message + * dhMAC [2] BIT STRING, -- Deprecated + * agreeMAC [3] PKMACValue, + * encryptedKey [4] EnvelopedData + * } + */ + +typedef struct ossl_crmf_popoprivkey_st { + int type; + union { + ASN1_BIT_STRING *thisMessage; /* 0 */ /* Deprecated */ + ASN1_INTEGER *subsequentMessage; /* 1 */ + ASN1_BIT_STRING *dhMAC; /* 2 */ /* Deprecated */ + OSSL_CRMF_PKMACVALUE *agreeMAC; /* 3 */ + ASN1_NULL *encryptedKey; /* 4 */ + } value; +} OSSL_CRMF_POPOPRIVKEY; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_POPOPRIVKEY) + +/*- + * PBMParameter ::= SEQUENCE { + * salt OCTET STRING, + * owf AlgorithmIdentifier, + * -- AlgId for a One-Way Function (SHA-1 recommended) + * iterationCount INTEGER, + * -- number of times the OWF is applied + * mac AlgorithmIdentifier + * -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11], + * -- or HMAC [HMAC, RFC2202]) + * } + */ +struct ossl_crmf_pbmparameter_st { + ASN1_OCTET_STRING *salt; + X509_ALGOR *owf; + ASN1_INTEGER *iterationCount; + X509_ALGOR *mac; +} /* OSSL_CRMF_PBMPARAMETER */; +# define OSSL_CRMF_PBM_MAX_ITERATION_COUNT 100000 /* if too large allows DoS */ + +/*- + * POPOSigningKeyInput ::= SEQUENCE { + * authInfo CHOICE { + * sender [0] GeneralName, + * -- used only if an authenticated identity has been + * -- established for the sender (e.g., a DN from a + * -- previously-issued and currently-valid certificate) + * publicKeyMAC PKMACValue }, + * -- used if no authenticated GeneralName currently exists for + * -- the sender; publicKeyMAC contains a password-based MAC + * -- on the DER-encoded value of publicKey + * publicKey SubjectPublicKeyInfo -- from CertTemplate + * } + */ +typedef struct ossl_crmf_poposigningkeyinput_authinfo_st { + int type; + union { + /* 0 */ GENERAL_NAME *sender; + /* 1 */ OSSL_CRMF_PKMACVALUE *publicKeyMAC; + } value; +} OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO) + +typedef struct ossl_crmf_poposigningkeyinput_st { + OSSL_CRMF_POPOSIGNINGKEYINPUT_AUTHINFO *authInfo; + X509_PUBKEY *publicKey; +} OSSL_CRMF_POPOSIGNINGKEYINPUT; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEYINPUT) + +/*- + * POPOSigningKey ::= SEQUENCE { + * poposkInput [0] POPOSigningKeyInput OPTIONAL, + * algorithmIdentifier AlgorithmIdentifier, + * signature BIT STRING + * } + */ +struct ossl_crmf_poposigningkey_st { + OSSL_CRMF_POPOSIGNINGKEYINPUT *poposkInput; + X509_ALGOR *algorithmIdentifier; + ASN1_BIT_STRING *signature; +} /* OSSL_CRMF_POPOSIGNINGKEY */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_POPOSIGNINGKEY) + +/*- + * ProofOfPossession ::= CHOICE { + * raVerified [0] NULL, + * -- used if the RA has already verified that the requester is in + * -- possession of the private key + * signature [1] POPOSigningKey, + * keyEncipherment [2] POPOPrivKey, + * keyAgreement [3] POPOPrivKey + * } + */ +typedef struct ossl_crmf_popo_st { + int type; + union { + ASN1_NULL *raVerified; /* 0 */ + OSSL_CRMF_POPOSIGNINGKEY *signature; /* 1 */ + OSSL_CRMF_POPOPRIVKEY *keyEncipherment; /* 2 */ + OSSL_CRMF_POPOPRIVKEY *keyAgreement; /* 3 */ + } value; +} OSSL_CRMF_POPO; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_POPO) + +/*- + * OptionalValidity ::= SEQUENCE { + * notBefore [0] Time OPTIONAL, + * notAfter [1] Time OPTIONAL -- at least one MUST be present + * } + */ +struct ossl_crmf_optionalvalidity_st { + /* 0 */ ASN1_TIME *notBefore; + /* 1 */ ASN1_TIME *notAfter; +} /* OSSL_CRMF_OPTIONALVALIDITY */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_OPTIONALVALIDITY) + +/*- + * CertTemplate ::= SEQUENCE { + * version [0] Version OPTIONAL, + * serialNumber [1] INTEGER OPTIONAL, + * signingAlg [2] AlgorithmIdentifier OPTIONAL, + * issuer [3] Name OPTIONAL, + * validity [4] OptionalValidity OPTIONAL, + * subject [5] Name OPTIONAL, + * publicKey [6] SubjectPublicKeyInfo OPTIONAL, + * issuerUID [7] UniqueIdentifier OPTIONAL, + * subjectUID [8] UniqueIdentifier OPTIONAL, + * extensions [9] Extensions OPTIONAL + * } + */ +struct ossl_crmf_certtemplate_st { + ASN1_INTEGER *version; + ASN1_INTEGER *serialNumber; /* serialNumber MUST be omitted */ + /* This field is assigned by the CA during certificate creation */ + X509_ALGOR *signingAlg; /* signingAlg MUST be omitted */ + /* This field is assigned by the CA during certificate creation */ + const X509_NAME *issuer; + OSSL_CRMF_OPTIONALVALIDITY *validity; + const X509_NAME *subject; + X509_PUBKEY *publicKey; + ASN1_BIT_STRING *issuerUID; /* deprecated in version 2 */ + /* According to rfc 3280: UniqueIdentifier ::= BIT STRING */ + ASN1_BIT_STRING *subjectUID; /* deprecated in version 2 */ + /* Could be X509_EXTENSION*S*, but that's only cosmetic */ + STACK_OF(X509_EXTENSION) *extensions; +} /* OSSL_CRMF_CERTTEMPLATE */; + +/*- + * CertRequest ::= SEQUENCE { + * certReqId INTEGER, -- ID for matching request and reply + * certTemplate CertTemplate, -- Selected fields of cert to be issued + * controls Controls OPTIONAL -- Attributes affecting issuance + * } + */ +struct ossl_crmf_certrequest_st { + ASN1_INTEGER *certReqId; + OSSL_CRMF_CERTTEMPLATE *certTemplate; + STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) *controls; +} /* OSSL_CRMF_CERTREQUEST */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTREQUEST) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTREQUEST) + +struct ossl_crmf_attributetypeandvalue_st { + ASN1_OBJECT *type; + union { + /* NID_id_regCtrl_regToken */ + ASN1_UTF8STRING *regToken; + + /* NID_id_regCtrl_authenticator */ + ASN1_UTF8STRING *authenticator; + + /* NID_id_regCtrl_pkiPublicationInfo */ + OSSL_CRMF_PKIPUBLICATIONINFO *pkiPublicationInfo; + + /* NID_id_regCtrl_oldCertID */ + OSSL_CRMF_CERTID *oldCertID; + + /* NID_id_regCtrl_protocolEncrKey */ + X509_PUBKEY *protocolEncrKey; + + /* NID_id_regInfo_utf8Pairs */ + ASN1_UTF8STRING *utf8Pairs; + + /* NID_id_regInfo_certReq */ + OSSL_CRMF_CERTREQUEST *certReq; + + ASN1_TYPE *other; + } value; +} /* OSSL_CRMF_ATTRIBUTETYPEANDVALUE */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +DEFINE_STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) + +/*- + * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg + * CertReqMsg ::= SEQUENCE { + * certReq CertRequest, + * popo ProofOfPossession OPTIONAL, + * -- content depends upon key type + * regInfo SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL + * } + */ +struct ossl_crmf_msg_st { + OSSL_CRMF_CERTREQUEST *certReq; + /* 0 */ + OSSL_CRMF_POPO *popo; + /* 1 */ + STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) *regInfo; +} /* OSSL_CRMF_MSG */; +#endif diff --git a/crypto/crmf/crmf_pbm.c b/crypto/crmf/crmf_pbm.c new file mode 100644 index 000000000000..88a8480cf73a --- /dev/null +++ b/crypto/crmf/crmf_pbm.c @@ -0,0 +1,233 @@ +/*- + * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2019 + * Copyright Siemens AG 2015-2019 + * + * 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 + * + * CRMF implementation by Martin Peylo, Miikka Viljanen, and David von Oheimb. + */ + + +#include <string.h> + +#include <openssl/rand.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> + +/* explicit #includes not strictly needed since implied by the above: */ +#include <openssl/asn1t.h> +#include <openssl/crmf.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/params.h> +#include <openssl/core_names.h> + +#include "internal/sizes.h" + +#include "crmf_local.h" + +/*- + * creates and initializes OSSL_CRMF_PBMPARAMETER (section 4.4) + * |slen| SHOULD be at least 8 (16 is common) + * |owfnid| e.g., NID_sha256 + * |itercnt| MUST be >= 100 (e.g., 500) and <= OSSL_CRMF_PBM_MAX_ITERATION_COUNT + * |macnid| e.g., NID_hmac_sha1 + * returns pointer to OSSL_CRMF_PBMPARAMETER on success, NULL on error + */ +OSSL_CRMF_PBMPARAMETER *OSSL_CRMF_pbmp_new(OSSL_LIB_CTX *libctx, size_t slen, + int owfnid, size_t itercnt, + int macnid) +{ + OSSL_CRMF_PBMPARAMETER *pbm = NULL; + unsigned char *salt = NULL; + + if ((pbm = OSSL_CRMF_PBMPARAMETER_new()) == NULL) + goto err; + + /* + * salt contains a randomly generated value used in computing the key + * of the MAC process. The salt SHOULD be at least 8 octets (64 + * bits) long. + */ + if ((salt = OPENSSL_malloc(slen)) == NULL) + goto err; + if (RAND_bytes_ex(libctx, salt, slen, 0) <= 0) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_FAILURE_OBTAINING_RANDOM); + goto err; + } + if (!ASN1_OCTET_STRING_set(pbm->salt, salt, (int)slen)) + goto err; + + /* + * owf identifies the hash algorithm and associated parameters used to + * compute the key used in the MAC process. All implementations MUST + * support SHA-1. + */ + if (!X509_ALGOR_set0(pbm->owf, OBJ_nid2obj(owfnid), V_ASN1_UNDEF, NULL)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_SETTING_OWF_ALGOR_FAILURE); + goto err; + } + + /* + * iterationCount identifies the number of times the hash is applied + * during the key computation process. The iterationCount MUST be a + * minimum of 100. Many people suggest using values as high as 1000 + * iterations as the minimum value. The trade off here is between + * protection of the password from attacks and the time spent by the + * server processing all of the different iterations in deriving + * passwords. Hashing is generally considered a cheap operation but + * this may not be true with all hash functions in the future. + */ + if (itercnt < 100) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ITERATIONCOUNT_BELOW_100); + goto err; + } + if (itercnt > OSSL_CRMF_PBM_MAX_ITERATION_COUNT) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT); + goto err; + } + + if (!ASN1_INTEGER_set(pbm->iterationCount, itercnt)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_CRMFERROR); + goto err; + } + + /* + * mac identifies the algorithm and associated parameters of the MAC + * function to be used. All implementations MUST support HMAC-SHA1 [HMAC]. + * All implementations SHOULD support DES-MAC and Triple-DES-MAC [PKCS11]. + */ + if (!X509_ALGOR_set0(pbm->mac, OBJ_nid2obj(macnid), V_ASN1_UNDEF, NULL)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_SETTING_MAC_ALGOR_FAILURE); + goto err; + } + + OPENSSL_free(salt); + return pbm; + err: + OPENSSL_free(salt); + OSSL_CRMF_PBMPARAMETER_free(pbm); + return NULL; +} + +/*- + * calculates the PBM based on the settings of the given OSSL_CRMF_PBMPARAMETER + * |pbmp| identifies the algorithms, salt to use + * |msg| message to apply the PBM for + * |msglen| length of the message + * |sec| key to use + * |seclen| length of the key + * |out| pointer to the computed mac, will be set on success + * |outlen| if not NULL, will set variable to the length of the mac on success + * returns 1 on success, 0 on error + */ +int OSSL_CRMF_pbm_new(OSSL_LIB_CTX *libctx, const char *propq, + const OSSL_CRMF_PBMPARAMETER *pbmp, + const unsigned char *msg, size_t msglen, + const unsigned char *sec, size_t seclen, + unsigned char **out, size_t *outlen) +{ + int mac_nid, hmac_md_nid = NID_undef; + char mdname[OSSL_MAX_NAME_SIZE]; + char hmac_mdname[OSSL_MAX_NAME_SIZE]; + EVP_MD *owf = NULL; + EVP_MD_CTX *ctx = NULL; + unsigned char basekey[EVP_MAX_MD_SIZE]; + unsigned int bklen = EVP_MAX_MD_SIZE; + int64_t iterations; + unsigned char *mac_res = 0; + int ok = 0; + + if (out == NULL || pbmp == NULL || pbmp->mac == NULL + || pbmp->mac->algorithm == NULL || msg == NULL || sec == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + goto err; + } + if ((mac_res = OPENSSL_malloc(EVP_MAX_MD_SIZE)) == NULL) + goto err; + + /* + * owf identifies the hash algorithm and associated parameters used to + * compute the key used in the MAC process. All implementations MUST + * support SHA-1. + */ + OBJ_obj2txt(mdname, sizeof(mdname), pbmp->owf->algorithm, 0); + if ((owf = EVP_MD_fetch(libctx, mdname, propq)) == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM); + goto err; + } + + if ((ctx = EVP_MD_CTX_new()) == NULL) + goto err; + + /* compute the basekey of the salted secret */ + if (!EVP_DigestInit_ex(ctx, owf, NULL)) + goto err; + /* first the secret */ + if (!EVP_DigestUpdate(ctx, sec, seclen)) + goto err; + /* then the salt */ + if (!EVP_DigestUpdate(ctx, pbmp->salt->data, pbmp->salt->length)) + goto err; + if (!EVP_DigestFinal_ex(ctx, basekey, &bklen)) + goto err; + if (!ASN1_INTEGER_get_int64(&iterations, pbmp->iterationCount) + || iterations < 100 /* min from RFC */ + || iterations > OSSL_CRMF_PBM_MAX_ITERATION_COUNT) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT); + goto err; + } + + /* the first iteration was already done above */ + while (--iterations > 0) { + if (!EVP_DigestInit_ex(ctx, owf, NULL)) + goto err; + if (!EVP_DigestUpdate(ctx, basekey, bklen)) + goto err; + if (!EVP_DigestFinal_ex(ctx, basekey, &bklen)) + goto err; + } + + /* + * mac identifies the algorithm and associated parameters of the MAC + * function to be used. All implementations MUST support HMAC-SHA1 [HMAC]. + * All implementations SHOULD support DES-MAC and Triple-DES-MAC [PKCS11]. + */ + mac_nid = OBJ_obj2nid(pbmp->mac->algorithm); + + if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, mac_nid, NULL, &hmac_md_nid, NULL) + || OBJ_obj2txt(hmac_mdname, sizeof(hmac_mdname), + OBJ_nid2obj(hmac_md_nid), 0) <= 0) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM); + goto err; + } + if (EVP_Q_mac(libctx, "HMAC", propq, hmac_mdname, NULL, basekey, bklen, + msg, msglen, mac_res, EVP_MAX_MD_SIZE, outlen) == NULL) + goto err; + + ok = 1; + + err: + OPENSSL_cleanse(basekey, bklen); + EVP_MD_free(owf); + EVP_MD_CTX_free(ctx); + + if (ok == 1) { + *out = mac_res; + return 1; + } + + OPENSSL_free(mac_res); + + if (pbmp != NULL && pbmp->mac != NULL) { + char buf[128]; + + if (OBJ_obj2txt(buf, sizeof(buf), pbmp->mac->algorithm, 0)) + ERR_add_error_data(1, buf); + } + return 0; +} |