1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00
Andrew Bartlett b12a33e225 third_party/heimdal: import lorikeet-heimdal-202311290849 (commit 84fb4579594a5fd8f8462450777eb24d5832be07)
Some of our pending PRs for Heimdal were recently accepted,
so this brings in a new update (mostly improved spelling).

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>

Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Thu Nov 30 21:25:56 UTC 2023 on atb-devel-224
2023-11-30 21:25:56 +00:00

2801 lines
69 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "hx_locl.h"
/*-
* RFC5758 specifies no parameters for ecdsa-with-SHA<N> signatures
* RFC5754 specifies NULL parameters for sha<N>WithRSAEncryption signatures
*
* XXX: Make sure that the parameters are either NULL in both the tbs and the
* signature, or absent from both the tbs and the signature.
*/
static const heim_octet_string null_entry_oid = { 2, rk_UNCONST("\x05\x00") };
static const unsigned sha512_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
const AlgorithmIdentifier _hx509_signature_sha512_data = {
{ 9, rk_UNCONST(sha512_oid_tree) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned sha384_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
const AlgorithmIdentifier _hx509_signature_sha384_data = {
{ 9, rk_UNCONST(sha384_oid_tree) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned sha256_oid_tree[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
const AlgorithmIdentifier _hx509_signature_sha256_data = {
{ 9, rk_UNCONST(sha256_oid_tree) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 };
const AlgorithmIdentifier _hx509_signature_sha1_data = {
{ 6, rk_UNCONST(sha1_oid_tree) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned md5_oid_tree[] = { 1, 2, 840, 113549, 2, 5 };
const AlgorithmIdentifier _hx509_signature_md5_data = {
{ 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 };
const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = {
{ 7, rk_UNCONST(rsa_with_sha512_oid) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_with_sha384_oid[] ={ 1, 2, 840, 113549, 1, 1, 12 };
const AlgorithmIdentifier _hx509_signature_rsa_with_sha384_data = {
{ 7, rk_UNCONST(rsa_with_sha384_oid) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_with_sha256_oid[] ={ 1, 2, 840, 113549, 1, 1, 11 };
const AlgorithmIdentifier _hx509_signature_rsa_with_sha256_data = {
{ 7, rk_UNCONST(rsa_with_sha256_oid) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_with_sha1_oid[] ={ 1, 2, 840, 113549, 1, 1, 5 };
const AlgorithmIdentifier _hx509_signature_rsa_with_sha1_data = {
{ 7, rk_UNCONST(rsa_with_sha1_oid) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_with_md5_oid[] ={ 1, 2, 840, 113549, 1, 1, 4 };
const AlgorithmIdentifier _hx509_signature_rsa_with_md5_data = {
{ 7, rk_UNCONST(rsa_with_md5_oid) }, rk_UNCONST(&null_entry_oid)
};
static const unsigned rsa_oid[] ={ 1, 2, 840, 113549, 1, 1, 1 };
const AlgorithmIdentifier _hx509_signature_rsa_data = {
{ 7, rk_UNCONST(rsa_oid) }, NULL
};
static const unsigned rsa_pkcs1_x509_oid[] ={ 1, 2, 752, 43, 16, 1 };
const AlgorithmIdentifier _hx509_signature_rsa_pkcs1_x509_data = {
{ 6, rk_UNCONST(rsa_pkcs1_x509_oid) }, NULL
};
static const unsigned des_rsdi_ede3_cbc_oid[] ={ 1, 2, 840, 113549, 3, 7 };
const AlgorithmIdentifier _hx509_des_rsdi_ede3_cbc_oid = {
{ 6, rk_UNCONST(des_rsdi_ede3_cbc_oid) }, NULL
};
static const unsigned aes128_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 2 };
const AlgorithmIdentifier _hx509_crypto_aes128_cbc_data = {
{ 9, rk_UNCONST(aes128_cbc_oid) }, NULL
};
static const unsigned aes256_cbc_oid[] ={ 2, 16, 840, 1, 101, 3, 4, 1, 42 };
const AlgorithmIdentifier _hx509_crypto_aes256_cbc_data = {
{ 9, rk_UNCONST(aes256_cbc_oid) }, NULL
};
/*
*
*/
static BIGNUM *
heim_int2BN(const heim_integer *i)
{
BIGNUM *bn;
bn = BN_bin2bn(i->data, i->length, NULL);
BN_set_negative(bn, i->negative);
return bn;
}
/*
*
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_set_digest_alg(DigestAlgorithmIdentifier *id,
const heim_oid *oid,
const void *param, size_t length)
{
int ret;
if (param) {
id->parameters = malloc(sizeof(*id->parameters));
if (id->parameters == NULL)
return ENOMEM;
id->parameters->data = malloc(length);
if (id->parameters->data == NULL) {
free(id->parameters);
id->parameters = NULL;
return ENOMEM;
}
memcpy(id->parameters->data, param, length);
id->parameters->length = length;
} else
id->parameters = NULL;
ret = der_copy_oid(oid, &id->algorithm);
if (ret) {
if (id->parameters) {
free(id->parameters->data);
free(id->parameters);
id->parameters = NULL;
}
return ret;
}
return 0;
}
/*
*
*/
static int
rsa_verify_signature(hx509_context context,
const struct signature_alg *sig_alg,
const Certificate *signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
const heim_octet_string *sig)
{
const SubjectPublicKeyInfo *spi;
DigestInfo di;
unsigned char *to;
int tosize, retsize;
int ret;
RSA *rsa;
size_t size;
const unsigned char *p;
memset(&di, 0, sizeof(di));
spi = &signer->tbsCertificate.subjectPublicKeyInfo;
p = spi->subjectPublicKey.data;
size = spi->subjectPublicKey.length / 8;
rsa = d2i_RSAPublicKey(NULL, &p, size);
if (rsa == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "out of memory");
goto out;
}
tosize = RSA_size(rsa);
to = malloc(tosize);
if (to == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "out of memory");
goto out;
}
retsize = RSA_public_decrypt(sig->length, (unsigned char *)sig->data,
to, rsa, RSA_PKCS1_PADDING);
if (retsize <= 0) {
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret,
"RSA public decrypt failed: %d", retsize);
free(to);
goto out;
}
if (retsize > tosize)
_hx509_abort("internal rsa decryption failure: ret > tosize");
if (sig_alg->flags & RA_RSA_USES_DIGEST_INFO) {
ret = decode_DigestInfo(to, retsize, &di, &size);
free(to);
if (ret) {
goto out;
}
/* Check for extra data inside the sigature */
if (size != (size_t)retsize) {
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret, "size from decryption mismatch");
goto out;
}
if (sig_alg->digest_alg &&
der_heim_oid_cmp(&di.digestAlgorithm.algorithm,
&sig_alg->digest_alg->algorithm) != 0)
{
ret = HX509_CRYPTO_OID_MISMATCH;
hx509_set_error_string(context, 0, ret, "object identifier in RSA sig mismatch");
goto out;
}
/* verify that the parameters are NULL or the NULL-type */
if (di.digestAlgorithm.parameters != NULL &&
(di.digestAlgorithm.parameters->length != 2 ||
memcmp(di.digestAlgorithm.parameters->data, "\x05\x00", 2) != 0))
{
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret, "Extra parameters inside RSA signature");
goto out;
}
ret = _hx509_verify_signature(context,
NULL,
&di.digestAlgorithm,
data,
&di.digest);
if (ret)
goto out;
} else {
if ((size_t)retsize != data->length ||
ct_memcmp(to, data->data, retsize) != 0)
{
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret, "RSA Signature incorrect");
goto out;
}
free(to);
ret = 0;
}
out:
free_DigestInfo(&di);
if (rsa)
RSA_free(rsa);
return ret;
}
static int
rsa_create_signature(hx509_context context,
const struct signature_alg *sig_alg,
const hx509_private_key signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
AlgorithmIdentifier *signatureAlgorithm,
heim_octet_string *sig)
{
const AlgorithmIdentifier *digest_alg;
heim_octet_string indata;
const heim_oid *sig_oid;
size_t size;
int ret;
if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) != 0)
return HX509_ALG_NOT_SUPP;
if (alg)
sig_oid = &alg->algorithm;
else
sig_oid = signer->signature_alg;
if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA512WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_sha512();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA384WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_sha384();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA256WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_sha256();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_sha1();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_md5();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION) == 0) {
digest_alg = hx509_signature_md5();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_DSA_WITH_SHA1) == 0) {
digest_alg = hx509_signature_sha1();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) {
digest_alg = hx509_signature_sha1();
} else if (der_heim_oid_cmp(sig_oid, ASN1_OID_ID_HEIM_RSA_PKCS1_X509) == 0) {
digest_alg = NULL;
} else
return HX509_ALG_NOT_SUPP;
if (signatureAlgorithm) {
ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid,
"\x05\x00", 2);
if (ret) {
hx509_clear_error_string(context);
return ret;
}
}
if (digest_alg) {
DigestInfo di;
memset(&di, 0, sizeof(di));
ret = _hx509_create_signature(context,
NULL,
digest_alg,
data,
&di.digestAlgorithm,
&di.digest);
if (ret)
return ret;
ASN1_MALLOC_ENCODE(DigestInfo,
indata.data,
indata.length,
&di,
&size,
ret);
free_DigestInfo(&di);
if (ret) {
hx509_set_error_string(context, 0, ret, "out of memory");
return ret;
}
if (indata.length != size)
_hx509_abort("internal ASN.1 encoder error");
} else {
indata = *data;
}
sig->length = RSA_size(signer->private_key.rsa);
sig->data = malloc(sig->length);
if (sig->data == NULL) {
der_free_octet_string(&indata);
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
ret = RSA_private_encrypt(indata.length, indata.data,
sig->data,
signer->private_key.rsa,
RSA_PKCS1_PADDING);
if (indata.data != data->data)
der_free_octet_string(&indata);
if (ret <= 0) {
ret = HX509_CMS_FAILED_CREATE_SIGATURE;
hx509_set_error_string(context, 0, ret,
"RSA private encrypt failed: %d", ret);
return ret;
}
if (sig->length > (size_t)ret) {
size = sig->length - ret;
memmove((uint8_t *)sig->data + size, sig->data, ret);
memset(sig->data, 0, size);
} else if (sig->length < (size_t)ret)
_hx509_abort("RSA signature prelen longer than output len");
return 0;
}
static int
rsa_private_key_import(hx509_context context,
const AlgorithmIdentifier *keyai,
const void *data,
size_t len,
hx509_key_format_t format,
hx509_private_key private_key)
{
switch (format) {
case HX509_KEY_FORMAT_DER: {
const unsigned char *p = data;
private_key->private_key.rsa =
d2i_RSAPrivateKey(NULL, &p, len);
if (private_key->private_key.rsa == NULL) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Failed to parse RSA key");
return HX509_PARSING_KEY_FAILED;
}
private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION;
break;
}
default:
return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED;
}
return 0;
}
static int
rsa_private_key2SPKI(hx509_context context,
hx509_private_key private_key,
SubjectPublicKeyInfo *spki)
{
int len, ret;
memset(spki, 0, sizeof(*spki));
len = i2d_RSAPublicKey(private_key->private_key.rsa, NULL);
if (len < 0)
return -1;
spki->subjectPublicKey.data = malloc(len);
if (spki->subjectPublicKey.data == NULL) {
hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
return ENOMEM;
}
spki->subjectPublicKey.length = len * 8;
ret = _hx509_set_digest_alg(&spki->algorithm,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
"\x05\x00", 2);
if (ret) {
hx509_set_error_string(context, 0, ret, "malloc - out of memory");
free(spki->subjectPublicKey.data);
spki->subjectPublicKey.data = NULL;
spki->subjectPublicKey.length = 0;
return ret;
}
{
unsigned char *pp = spki->subjectPublicKey.data;
i2d_RSAPublicKey(private_key->private_key.rsa, &pp);
}
return 0;
}
static int
rsa_generate_private_key(hx509_context context,
struct hx509_generate_private_context *ctx,
hx509_private_key private_key)
{
BIGNUM *e;
int ret;
unsigned long bits;
static const int default_rsa_e = 65537;
static const int default_rsa_bits = 2048;
private_key->private_key.rsa = RSA_new();
if (private_key->private_key.rsa == NULL) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Failed to generate RSA key");
return HX509_PARSING_KEY_FAILED;
}
e = BN_new();
BN_set_word(e, default_rsa_e);
bits = default_rsa_bits;
if (ctx->num_bits)
bits = ctx->num_bits;
ret = RSA_generate_key_ex(private_key->private_key.rsa, bits, e, NULL);
BN_free(e);
if (ret != 1) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Failed to generate RSA key");
return HX509_PARSING_KEY_FAILED;
}
private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION;
return 0;
}
static int
rsa_private_key_export(hx509_context context,
const hx509_private_key key,
hx509_key_format_t format,
heim_octet_string *data)
{
int ret;
data->data = NULL;
data->length = 0;
switch (format) {
case HX509_KEY_FORMAT_DER:
ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL);
if (ret <= 0) {
ret = EINVAL;
hx509_set_error_string(context, 0, ret,
"Private key is not exportable");
return ret;
}
data->data = malloc(ret);
if (data->data == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "malloc out of memory");
return ret;
}
data->length = ret;
{
unsigned char *p = data->data;
i2d_RSAPrivateKey(key->private_key.rsa, &p);
}
break;
default:
return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED;
}
return 0;
}
static BIGNUM *
rsa_get_internal(hx509_context context,
hx509_private_key key,
const char *type)
{
if (strcasecmp(type, "rsa-modulus") == 0) {
return BN_dup(key->private_key.rsa->n);
} else if (strcasecmp(type, "rsa-exponent") == 0) {
return BN_dup(key->private_key.rsa->e);
} else
return NULL;
}
static hx509_private_key_ops rsa_private_key_ops = {
"RSA PRIVATE KEY",
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
NULL,
rsa_private_key2SPKI,
rsa_private_key_export,
rsa_private_key_import,
rsa_generate_private_key,
rsa_get_internal
};
/*
*
*/
static int
dsa_verify_signature(hx509_context context,
const struct signature_alg *sig_alg,
const Certificate *signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
const heim_octet_string *sig)
{
const SubjectPublicKeyInfo *spi;
DSAPublicKey pk;
DSAParams param;
size_t size;
DSA *dsa;
int ret;
spi = &signer->tbsCertificate.subjectPublicKeyInfo;
dsa = DSA_new();
if (dsa == NULL) {
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
ret = decode_DSAPublicKey(spi->subjectPublicKey.data,
spi->subjectPublicKey.length / 8,
&pk, &size);
if (ret)
goto out;
dsa->pub_key = heim_int2BN(&pk);
free_DSAPublicKey(&pk);
if (dsa->pub_key == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "out of memory");
goto out;
}
if (spi->algorithm.parameters == NULL) {
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret, "DSA parameters missing");
goto out;
}
ret = decode_DSAParams(spi->algorithm.parameters->data,
spi->algorithm.parameters->length,
&param,
&size);
if (ret) {
hx509_set_error_string(context, 0, ret, "DSA parameters failed to decode");
goto out;
}
dsa->p = heim_int2BN(&param.p);
dsa->q = heim_int2BN(&param.q);
dsa->g = heim_int2BN(&param.g);
free_DSAParams(&param);
if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "out of memory");
goto out;
}
ret = DSA_verify(-1, data->data, data->length,
(unsigned char*)sig->data, sig->length,
dsa);
if (ret == 1)
ret = 0;
else if (ret == 0 || ret == -1) {
ret = HX509_CRYPTO_BAD_SIGNATURE;
hx509_set_error_string(context, 0, ret, "BAD DSA sigature");
} else {
ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
hx509_set_error_string(context, 0, ret, "Invalid format of DSA sigature");
}
out:
DSA_free(dsa);
return ret;
}
#if 0
static int
dsa_parse_private_key(hx509_context context,
const void *data,
size_t len,
hx509_private_key private_key)
{
const unsigned char *p = data;
private_key->private_key.dsa =
d2i_DSAPrivateKey(NULL, &p, len);
if (private_key->private_key.dsa == NULL)
return EINVAL;
private_key->signature_alg = ASN1_OID_ID_DSA_WITH_SHA1;
return 0;
/* else */
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"No support to parse DSA keys");
return HX509_PARSING_KEY_FAILED;
}
#endif
static int
evp_md_create_signature(hx509_context context,
const struct signature_alg *sig_alg,
const hx509_private_key signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
AlgorithmIdentifier *signatureAlgorithm,
heim_octet_string *sig)
{
size_t sigsize = EVP_MD_size(sig_alg->evp_md());
EVP_MD_CTX *ctx;
memset(sig, 0, sizeof(*sig));
if (signatureAlgorithm) {
int ret;
ret = _hx509_set_digest_alg(signatureAlgorithm,
sig_alg->sig_oid, "\x05\x00", 2);
if (ret)
return ret;
}
sig->data = malloc(sigsize);
if (sig->data == NULL) {
sig->length = 0;
return ENOMEM;
}
sig->length = sigsize;
ctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(ctx, sig_alg->evp_md(), NULL);
EVP_DigestUpdate(ctx, data->data, data->length);
EVP_DigestFinal_ex(ctx, sig->data, NULL);
EVP_MD_CTX_destroy(ctx);
return 0;
}
static int
evp_md_verify_signature(hx509_context context,
const struct signature_alg *sig_alg,
const Certificate *signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
const heim_octet_string *sig)
{
unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD_CTX *ctx;
size_t sigsize = EVP_MD_size(sig_alg->evp_md());
if (sig->length != sigsize || sigsize > sizeof(digest)) {
hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
"SHA256 sigature has wrong length");
return HX509_CRYPTO_SIG_INVALID_FORMAT;
}
ctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(ctx, sig_alg->evp_md(), NULL);
EVP_DigestUpdate(ctx, data->data, data->length);
EVP_DigestFinal_ex(ctx, digest, NULL);
EVP_MD_CTX_destroy(ctx);
if (ct_memcmp(digest, sig->data, sigsize) != 0) {
hx509_set_error_string(context, 0, HX509_CRYPTO_BAD_SIGNATURE,
"Bad %s sigature", sig_alg->name);
return HX509_CRYPTO_BAD_SIGNATURE;
}
return 0;
}
#ifdef HAVE_HCRYPTO_W_OPENSSL
extern const struct signature_alg ecdsa_with_sha512_alg;
extern const struct signature_alg ecdsa_with_sha384_alg;
extern const struct signature_alg ecdsa_with_sha256_alg;
extern const struct signature_alg ecdsa_with_sha1_alg;
#endif
static const struct signature_alg heim_rsa_pkcs1_x509 = {
"rsa-pkcs1-x509",
ASN1_OID_ID_HEIM_RSA_PKCS1_X509,
&_hx509_signature_rsa_pkcs1_x509_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
NULL,
PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg pkcs1_rsa_sha1_alg = {
"rsa",
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_rsa_with_sha1_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
NULL,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_sha512_alg = {
"rsa-with-sha512",
ASN1_OID_ID_PKCS1_SHA512WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_sha512_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_sha512_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_sha384_alg = {
"rsa-with-sha384",
ASN1_OID_ID_PKCS1_SHA384WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_sha384_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_sha384_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_sha256_alg = {
"rsa-with-sha256",
ASN1_OID_ID_PKCS1_SHA256WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_sha256_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_sha256_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_sha1_alg = {
"rsa-with-sha1",
ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_sha1_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_sha1_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_sha1_alg_secsig = {
"rsa-with-sha1",
ASN1_OID_ID_SECSIG_SHA_1WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_sha1_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_sha1_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK,
0,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg rsa_with_md5_alg = {
"rsa-with-md5",
ASN1_OID_ID_PKCS1_MD5WITHRSAENCRYPTION,
&_hx509_signature_rsa_with_md5_data,
ASN1_OID_ID_PKCS1_RSAENCRYPTION,
&_hx509_signature_md5_data,
PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|WEAK_SIG_ALG,
1230739889,
NULL,
rsa_verify_signature,
rsa_create_signature,
0
};
static const struct signature_alg dsa_sha1_alg = {
"dsa-with-sha1",
ASN1_OID_ID_DSA_WITH_SHA1,
NULL,
ASN1_OID_ID_DSA,
&_hx509_signature_sha1_data,
PROVIDE_CONF|REQUIRE_SIGNER|SIG_PUBLIC_SIG,
0,
NULL,
dsa_verify_signature,
/* create_signature */ NULL,
0
};
static const struct signature_alg sha512_alg = {
"sha-512",
ASN1_OID_ID_SHA512,
&_hx509_signature_sha512_data,
NULL,
NULL,
SIG_DIGEST,
0,
EVP_sha512,
evp_md_verify_signature,
evp_md_create_signature,
0
};
static const struct signature_alg sha384_alg = {
"sha-384",
ASN1_OID_ID_SHA384,
&_hx509_signature_sha384_data,
NULL,
NULL,
SIG_DIGEST,
0,
EVP_sha384,
evp_md_verify_signature,
evp_md_create_signature,
0
};
static const struct signature_alg sha256_alg = {
"sha-256",
ASN1_OID_ID_SHA256,
&_hx509_signature_sha256_data,
NULL,
NULL,
SIG_DIGEST,
0,
EVP_sha256,
evp_md_verify_signature,
evp_md_create_signature,
0
};
static const struct signature_alg sha1_alg = {
"sha1",
ASN1_OID_ID_SECSIG_SHA_1,
&_hx509_signature_sha1_data,
NULL,
NULL,
SIG_DIGEST,
0,
EVP_sha1,
evp_md_verify_signature,
evp_md_create_signature,
0
};
static const struct signature_alg md5_alg = {
"rsa-md5",
ASN1_OID_ID_RSA_DIGEST_MD5,
&_hx509_signature_md5_data,
NULL,
NULL,
SIG_DIGEST|WEAK_SIG_ALG,
0,
EVP_md5,
evp_md_verify_signature,
NULL,
0
};
/*
* Order matter in this structure, "best" first for each "key
* compatible" type (type is ECDSA, RSA, DSA, none, etc)
*/
static const struct signature_alg *sig_algs[] = {
#ifdef HAVE_HCRYPTO_W_OPENSSL
&ecdsa_with_sha512_alg,
&ecdsa_with_sha384_alg,
&ecdsa_with_sha256_alg,
&ecdsa_with_sha1_alg,
#endif
&rsa_with_sha512_alg,
&rsa_with_sha384_alg,
&rsa_with_sha256_alg,
&rsa_with_sha1_alg,
&rsa_with_sha1_alg_secsig,
&pkcs1_rsa_sha1_alg,
&rsa_with_md5_alg,
&heim_rsa_pkcs1_x509,
&dsa_sha1_alg,
&sha512_alg,
&sha384_alg,
&sha256_alg,
&sha1_alg,
&md5_alg,
NULL
};
const struct signature_alg *
_hx509_find_sig_alg(const heim_oid *oid)
{
unsigned int i;
for (i = 0; sig_algs[i]; i++)
if (der_heim_oid_cmp(sig_algs[i]->sig_oid, oid) == 0)
return sig_algs[i];
return NULL;
}
static const AlgorithmIdentifier *
alg_for_privatekey(const hx509_private_key pk, int type)
{
const heim_oid *keytype;
unsigned int i;
if (pk->ops == NULL)
return NULL;
keytype = pk->ops->key_oid;
for (i = 0; sig_algs[i]; i++) {
if (sig_algs[i]->key_oid == NULL)
continue;
if (der_heim_oid_cmp(sig_algs[i]->key_oid, keytype) != 0)
continue;
if (pk->ops->available &&
pk->ops->available(pk, sig_algs[i]->sig_alg) == 0)
continue;
if (type == HX509_SELECT_PUBLIC_SIG)
return sig_algs[i]->sig_alg;
if (type == HX509_SELECT_DIGEST)
return sig_algs[i]->digest_alg;
return NULL;
}
return NULL;
}
/*
*
*/
#ifdef HAVE_HCRYPTO_W_OPENSSL
extern hx509_private_key_ops ecdsa_private_key_ops;
#endif
static struct hx509_private_key_ops *private_algs[] = {
&rsa_private_key_ops,
#ifdef HAVE_HCRYPTO_W_OPENSSL
&ecdsa_private_key_ops,
#endif
NULL
};
HX509_LIB_FUNCTION hx509_private_key_ops * HX509_LIB_CALL
hx509_find_private_alg(const heim_oid *oid)
{
int i;
for (i = 0; private_algs[i]; i++) {
if (private_algs[i]->key_oid == NULL)
continue;
if (der_heim_oid_cmp(private_algs[i]->key_oid, oid) == 0)
return private_algs[i];
}
return NULL;
}
/*
* Check if the algorithm `alg' have a best before date, and if it
* des, make sure the its before the time `t'.
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_signature_is_weak(hx509_context context, const AlgorithmIdentifier *alg)
{
const struct signature_alg *md;
md = _hx509_find_sig_alg(&alg->algorithm);
if (md == NULL) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_NO_SUPPORTED;
}
if (md->flags & WEAK_SIG_ALG) {
hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE,
"Algorithm %s is weak", md->name);
return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
}
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_self_signed_valid(hx509_context context,
const AlgorithmIdentifier *alg)
{
const struct signature_alg *md;
md = _hx509_find_sig_alg(&alg->algorithm);
if (md == NULL) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_NO_SUPPORTED;
}
if ((md->flags & SELF_SIGNED_OK) == 0) {
hx509_set_error_string(context, 0, HX509_CRYPTO_ALGORITHM_BEST_BEFORE,
"Algorithm %s not trusted for self signatures",
md->name);
return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
}
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_verify_signature(hx509_context context,
const hx509_cert cert,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
const heim_octet_string *sig)
{
const struct signature_alg *md;
const Certificate *signer = NULL;
if (cert)
signer = _hx509_get_cert(cert);
md = _hx509_find_sig_alg(&alg->algorithm);
if (md == NULL) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_NO_SUPPORTED;
}
if (signer && (md->flags & PROVIDE_CONF) == 0) {
hx509_clear_error_string(context);
return HX509_CRYPTO_SIG_NO_CONF;
}
if (signer == NULL && (md->flags & REQUIRE_SIGNER)) {
hx509_clear_error_string(context);
return HX509_CRYPTO_SIGNATURE_WITHOUT_SIGNER;
}
if (md->key_oid && signer) {
const SubjectPublicKeyInfo *spi;
spi = &signer->tbsCertificate.subjectPublicKeyInfo;
if (der_heim_oid_cmp(&spi->algorithm.algorithm, md->key_oid) != 0) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_DONT_MATCH_KEY_ALG;
}
}
return (*md->verify_signature)(context, md, signer, alg, data, sig);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_create_signature(hx509_context context,
const hx509_private_key signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
AlgorithmIdentifier *signatureAlgorithm,
heim_octet_string *sig)
{
const struct signature_alg *md;
md = _hx509_find_sig_alg(&alg->algorithm);
if (md == NULL) {
hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED,
"algorithm no supported");
return HX509_SIG_ALG_NO_SUPPORTED;
}
if (signer && (md->flags & PROVIDE_CONF) == 0) {
hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED,
"algorithm provides no conf");
return HX509_CRYPTO_SIG_NO_CONF;
}
return (*md->create_signature)(context, md, signer, alg, data,
signatureAlgorithm, sig);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_create_signature_bitstring(hx509_context context,
const hx509_private_key signer,
const AlgorithmIdentifier *alg,
const heim_octet_string *data,
AlgorithmIdentifier *signatureAlgorithm,
heim_bit_string *sig)
{
heim_octet_string os;
int ret;
ret = _hx509_create_signature(context, signer, alg,
data, signatureAlgorithm, &os);
if (ret)
return ret;
sig->data = os.data;
sig->length = os.length * 8;
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_public_encrypt(hx509_context context,
const heim_octet_string *cleartext,
const Certificate *cert,
heim_oid *encryption_oid,
heim_octet_string *ciphertext)
{
const SubjectPublicKeyInfo *spi;
unsigned char *to;
int tosize;
int ret;
RSA *rsa;
size_t size;
const unsigned char *p;
ciphertext->data = NULL;
ciphertext->length = 0;
spi = &cert->tbsCertificate.subjectPublicKeyInfo;
p = spi->subjectPublicKey.data;
size = spi->subjectPublicKey.length / 8;
rsa = d2i_RSAPublicKey(NULL, &p, size);
if (rsa == NULL) {
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
tosize = RSA_size(rsa);
to = malloc(tosize);
if (to == NULL) {
RSA_free(rsa);
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
ret = RSA_public_encrypt(cleartext->length,
(unsigned char *)cleartext->data,
to, rsa, RSA_PKCS1_PADDING);
RSA_free(rsa);
if (ret <= 0) {
free(to);
hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PUBLIC_ENCRYPT,
"RSA public encrypt failed with %d", ret);
return HX509_CRYPTO_RSA_PUBLIC_ENCRYPT;
}
if (ret > tosize)
_hx509_abort("internal rsa decryption failure: ret > tosize");
ciphertext->length = ret;
ciphertext->data = to;
ret = der_copy_oid(ASN1_OID_ID_PKCS1_RSAENCRYPTION, encryption_oid);
if (ret) {
der_free_octet_string(ciphertext);
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_private_key_private_decrypt(hx509_context context,
const heim_octet_string *ciphertext,
const heim_oid *encryption_oid,
hx509_private_key p,
heim_octet_string *cleartext)
{
int ret;
cleartext->data = NULL;
cleartext->length = 0;
if (p->private_key.rsa == NULL) {
hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
"Private RSA key missing");
return HX509_PRIVATE_KEY_MISSING;
}
cleartext->length = RSA_size(p->private_key.rsa);
cleartext->data = malloc(cleartext->length);
if (cleartext->data == NULL) {
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
ret = RSA_private_decrypt(ciphertext->length, ciphertext->data,
cleartext->data,
p->private_key.rsa,
RSA_PKCS1_PADDING);
if (ret <= 0) {
der_free_octet_string(cleartext);
hx509_set_error_string(context, 0, HX509_CRYPTO_RSA_PRIVATE_DECRYPT,
"Failed to decrypt using private key: %d", ret);
return HX509_CRYPTO_RSA_PRIVATE_DECRYPT;
}
if (cleartext->length < (size_t)ret)
_hx509_abort("internal rsa decryption failure: ret > tosize");
cleartext->length = ret;
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_parse_private_key(hx509_context context,
const AlgorithmIdentifier *keyai,
const void *data,
size_t len,
hx509_key_format_t format,
hx509_private_key *private_key)
{
struct hx509_private_key_ops *ops;
int ret;
*private_key = NULL;
ops = hx509_find_private_alg(&keyai->algorithm);
if (ops == NULL) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_NO_SUPPORTED;
}
ret = hx509_private_key_init(private_key, ops, NULL);
if (ret) {
hx509_set_error_string(context, 0, ret, "out of memory");
return ret;
}
ret = (*ops->import)(context, keyai, data, len, format, *private_key);
if (ret)
hx509_private_key_free(private_key);
if (ret && format == HX509_KEY_FORMAT_PKCS8) {
PKCS8PrivateKeyInfo ki;
hx509_private_key key;
/* Re-enter to try parsing the DER-encoded key from PKCS#8 envelope */
ret = decode_PKCS8PrivateKeyInfo(data, len, &ki, NULL);
if (ret) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Failed to parse PKCS#8-encoded private "
"key");
return HX509_PARSING_KEY_FAILED;
}
ret = hx509_parse_private_key(context, &ki.privateKeyAlgorithm,
ki.privateKey.data, ki.privateKey.length,
HX509_KEY_FORMAT_DER, &key);
free_PKCS8PrivateKeyInfo(&ki);
if (ret) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Failed to parse RSA key from PKCS#8 "
"envelope");
return HX509_PARSING_KEY_FAILED;
}
*private_key = key;
}
return ret;
}
/*
*
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_private_key2SPKI(hx509_context context,
hx509_private_key private_key,
SubjectPublicKeyInfo *spki)
{
const struct hx509_private_key_ops *ops = private_key->ops;
if (ops == NULL || ops->get_spki == NULL) {
hx509_set_error_string(context, 0, HX509_UNIMPLEMENTED_OPERATION,
"Private key have no key2SPKI function");
return HX509_UNIMPLEMENTED_OPERATION;
}
return (*ops->get_spki)(context, private_key, spki);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_generate_private_key_init(hx509_context context,
const heim_oid *oid,
struct hx509_generate_private_context **ctx)
{
*ctx = NULL;
if (der_heim_oid_cmp(oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) != 0) {
hx509_set_error_string(context, 0, EINVAL,
"private key not an RSA key");
return EINVAL;
}
*ctx = calloc(1, sizeof(**ctx));
if (*ctx == NULL) {
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
(*ctx)->key_oid = oid;
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_generate_private_key_is_ca(hx509_context context,
struct hx509_generate_private_context *ctx)
{
ctx->isCA = 1;
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_generate_private_key_bits(hx509_context context,
struct hx509_generate_private_context *ctx,
unsigned long bits)
{
ctx->num_bits = bits;
return 0;
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
_hx509_generate_private_key_free(struct hx509_generate_private_context **ctx)
{
free(*ctx);
*ctx = NULL;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_generate_private_key(hx509_context context,
struct hx509_generate_private_context *ctx,
hx509_private_key *private_key)
{
struct hx509_private_key_ops *ops;
int ret;
*private_key = NULL;
ops = hx509_find_private_alg(ctx->key_oid);
if (ops == NULL) {
hx509_clear_error_string(context);
return HX509_SIG_ALG_NO_SUPPORTED;
}
ret = hx509_private_key_init(private_key, ops, NULL);
if (ret) {
hx509_set_error_string(context, 0, ret, "out of memory");
return ret;
}
ret = (*ops->generate_private_key)(context, ctx, *private_key);
if (ret)
hx509_private_key_free(private_key);
return ret;
}
/*
*
*/
const AlgorithmIdentifier *
hx509_signature_sha512(void)
{ return &_hx509_signature_sha512_data; }
const AlgorithmIdentifier *
hx509_signature_sha384(void)
{ return &_hx509_signature_sha384_data; }
const AlgorithmIdentifier *
hx509_signature_sha256(void)
{ return &_hx509_signature_sha256_data; }
const AlgorithmIdentifier *
hx509_signature_sha1(void)
{ return &_hx509_signature_sha1_data; }
const AlgorithmIdentifier *
hx509_signature_md5(void)
{ return &_hx509_signature_md5_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_with_sha512(void)
{ return &_hx509_signature_rsa_with_sha512_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_with_sha384(void)
{ return &_hx509_signature_rsa_with_sha384_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_with_sha256(void)
{ return &_hx509_signature_rsa_with_sha256_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_with_sha1(void)
{ return &_hx509_signature_rsa_with_sha1_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_with_md5(void)
{ return &_hx509_signature_rsa_with_md5_data; }
const AlgorithmIdentifier *
hx509_signature_rsa(void)
{ return &_hx509_signature_rsa_data; }
const AlgorithmIdentifier *
hx509_signature_rsa_pkcs1_x509(void)
{ return &_hx509_signature_rsa_pkcs1_x509_data; }
const AlgorithmIdentifier *
hx509_crypto_des_rsdi_ede3_cbc(void)
{ return &_hx509_des_rsdi_ede3_cbc_oid; }
const AlgorithmIdentifier *
hx509_crypto_aes128_cbc(void)
{ return &_hx509_crypto_aes128_cbc_data; }
const AlgorithmIdentifier *
hx509_crypto_aes256_cbc(void)
{ return &_hx509_crypto_aes256_cbc_data; }
/*
*
*/
const AlgorithmIdentifier * _hx509_crypto_default_sig_alg =
&_hx509_signature_rsa_with_sha256_data;
const AlgorithmIdentifier * _hx509_crypto_default_digest_alg =
&_hx509_signature_sha256_data;
const AlgorithmIdentifier * _hx509_crypto_default_secret_alg =
&_hx509_crypto_aes128_cbc_data;
/*
*
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_private_key_init(hx509_private_key *key,
hx509_private_key_ops *ops,
void *keydata)
{
*key = calloc(1, sizeof(**key));
if (*key == NULL)
return ENOMEM;
(*key)->ref = 1;
(*key)->ops = ops;
(*key)->private_key.keydata = keydata;
return 0;
}
HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL
_hx509_private_key_ref(hx509_private_key key)
{
if (key->ref == 0)
_hx509_abort("key refcount <= 0 on ref");
key->ref++;
if (key->ref == UINT_MAX)
_hx509_abort("key refcount == UINT_MAX on ref");
return key;
}
HX509_LIB_FUNCTION const char * HX509_LIB_CALL
_hx509_private_pem_name(hx509_private_key key)
{
return key->ops->pemtype;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_private_key_free(hx509_private_key *key)
{
if (key == NULL || *key == NULL)
return 0;
if ((*key)->ref == 0)
_hx509_abort("key refcount == 0 on free");
if (--(*key)->ref > 0)
return 0;
if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) {
if ((*key)->private_key.rsa)
RSA_free((*key)->private_key.rsa);
} else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid,
ASN1_OID_ID_ECPUBLICKEY) == 0 &&
(*key)->private_key.ecdsa != NULL) {
_hx509_private_eckey_free((*key)->private_key.ecdsa);
}
(*key)->private_key.rsa = NULL;
free(*key);
*key = NULL;
return 0;
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
hx509_private_key_assign_rsa(hx509_private_key key, void *ptr)
{
if (key->private_key.rsa)
RSA_free(key->private_key.rsa);
key->private_key.rsa = ptr;
key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION;
key->md = &pkcs1_rsa_sha1_alg;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_private_key_oid(hx509_context context,
const hx509_private_key key,
heim_oid *data)
{
int ret;
ret = der_copy_oid(key->ops->key_oid, data);
if (ret)
hx509_set_error_string(context, 0, ret, "malloc out of memory");
return ret;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_private_key_exportable(hx509_private_key key)
{
if (key->ops->export == NULL)
return 0;
return 1;
}
HX509_LIB_FUNCTION BIGNUM * HX509_LIB_CALL
_hx509_private_key_get_internal(hx509_context context,
hx509_private_key key,
const char *type)
{
if (key->ops->get_internal == NULL)
return NULL;
return (*key->ops->get_internal)(context, key, type);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_private_key_export(hx509_context context,
const hx509_private_key key,
hx509_key_format_t format,
heim_octet_string *data)
{
data->length = 0;
data->data = NULL;
if (key->ops->export == NULL) {
hx509_clear_error_string(context);
return HX509_UNIMPLEMENTED_OPERATION;
}
if (format == HX509_KEY_FORMAT_PKCS8) {
PKCS8PrivateKeyInfo ki;
size_t size;
int ret;
memset(&ki, 0, sizeof(ki));
ki.attributes = NULL; /* No localKeyId needed */
ki.privateKey.data = NULL;
ki.privateKeyAlgorithm.algorithm.components = NULL;
ret = der_parse_hex_heim_integer("00", &ki.version);
if (ret == 0)
ret = _hx509_private_key_oid(context, key,
&ki.privateKeyAlgorithm.algorithm);
if (ret == 0)
/* Re-enter */
ret = _hx509_private_key_export(context, key, HX509_KEY_FORMAT_DER,
&ki.privateKey);
/*
* XXX To set ki.privateKeyAlgorithm.parameters we'll need to either
* move this code into the *key->ops->export() functions, or expand
* their signature to allow them to set it for us, or add a method to
* hx509_private_key_ops that allows us to get the parameters from the
* backend.
*/
ki.privateKeyAlgorithm.parameters = NULL;
if (ret == 0)
ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, data->data, data->length,
&ki, &size, ret);
free_PKCS8PrivateKeyInfo(&ki);
if (ret == 0 && size != data->length)
ret = EINVAL;
if (ret)
hx509_set_error_string(context, 0, ret,
"Private key PKCS#8 encoding failed");
return ret;
}
return (*key->ops->export)(context, key, format, data);
}
/*
*
*/
struct hx509cipher {
const char *name;
int flags;
#define CIPHER_WEAK 1
const heim_oid *oid;
const AlgorithmIdentifier *(*ai_func)(void);
const EVP_CIPHER *(*evp_func)(void);
int (*get_params)(hx509_context, const hx509_crypto,
const heim_octet_string *, heim_octet_string *);
int (*set_params)(hx509_context, const heim_octet_string *,
hx509_crypto, heim_octet_string *);
};
struct hx509_crypto_data {
char *name;
int flags;
#define ALLOW_WEAK 1
#define PADDING_NONE 2
#define PADDING_PKCS7 4
#define PADDING_FLAGS (2|4)
const struct hx509cipher *cipher;
const EVP_CIPHER *c;
heim_octet_string key;
heim_oid oid;
void *param;
};
/*
*
*/
static unsigned private_rc2_40_oid_data[] = { 127, 1 };
static heim_oid asn1_oid_private_rc2_40 =
{ 2, private_rc2_40_oid_data };
/*
*
*/
static int
CMSCBCParam_get(hx509_context context, const hx509_crypto crypto,
const heim_octet_string *ivec, heim_octet_string *param)
{
size_t size;
int ret;
assert(crypto->param == NULL);
if (ivec == NULL)
return 0;
ASN1_MALLOC_ENCODE(CMSCBCParameter, param->data, param->length,
ivec, &size, ret);
if (ret == 0 && size != param->length)
_hx509_abort("Internal asn1 encoder failure");
if (ret)
hx509_clear_error_string(context);
return ret;
}
static int
CMSCBCParam_set(hx509_context context, const heim_octet_string *param,
hx509_crypto crypto, heim_octet_string *ivec)
{
int ret;
if (ivec == NULL)
return 0;
ret = decode_CMSCBCParameter(param->data, param->length, ivec, NULL);
if (ret)
hx509_clear_error_string(context);
return ret;
}
struct _RC2_params {
int maximum_effective_key;
};
static int
CMSRC2CBCParam_get(hx509_context context, const hx509_crypto crypto,
const heim_octet_string *ivec, heim_octet_string *param)
{
CMSRC2CBCParameter rc2params;
const struct _RC2_params *p = crypto->param;
int maximum_effective_key = 128;
size_t size;
int ret;
memset(&rc2params, 0, sizeof(rc2params));
if (p)
maximum_effective_key = p->maximum_effective_key;
switch(maximum_effective_key) {
case 40:
rc2params.rc2ParameterVersion = 160;
break;
case 64:
rc2params.rc2ParameterVersion = 120;
break;
case 128:
rc2params.rc2ParameterVersion = 58;
break;
}
rc2params.iv = *ivec;
ASN1_MALLOC_ENCODE(CMSRC2CBCParameter, param->data, param->length,
&rc2params, &size, ret);
if (ret == 0 && size != param->length)
_hx509_abort("Internal asn1 encoder failure");
return ret;
}
static int
CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param,
hx509_crypto crypto, heim_octet_string *ivec)
{
CMSRC2CBCParameter rc2param;
struct _RC2_params *p;
size_t size;
int ret;
ret = decode_CMSRC2CBCParameter(param->data, param->length,
&rc2param, &size);
if (ret) {
hx509_clear_error_string(context);
return ret;
}
p = calloc(1, sizeof(*p));
if (p == NULL) {
free_CMSRC2CBCParameter(&rc2param);
hx509_clear_error_string(context);
return ENOMEM;
}
switch(rc2param.rc2ParameterVersion) {
case 160:
crypto->c = EVP_rc2_40_cbc();
p->maximum_effective_key = 40;
break;
case 120:
crypto->c = EVP_rc2_64_cbc();
p->maximum_effective_key = 64;
break;
case 58:
crypto->c = EVP_rc2_cbc();
p->maximum_effective_key = 128;
break;
default:
free(p);
free_CMSRC2CBCParameter(&rc2param);
return HX509_CRYPTO_SIG_INVALID_FORMAT;
}
if (ivec)
ret = der_copy_octet_string(&rc2param.iv, ivec);
free_CMSRC2CBCParameter(&rc2param);
if (ret) {
free(p);
hx509_clear_error_string(context);
} else
crypto->param = p;
return ret;
}
/*
*
*/
static const struct hx509cipher ciphers[] = {
{
"rc2-cbc",
CIPHER_WEAK,
ASN1_OID_ID_PKCS3_RC2_CBC,
NULL,
EVP_rc2_cbc,
CMSRC2CBCParam_get,
CMSRC2CBCParam_set
},
{
"rc2-cbc",
CIPHER_WEAK,
ASN1_OID_ID_RSADSI_RC2_CBC,
NULL,
EVP_rc2_cbc,
CMSRC2CBCParam_get,
CMSRC2CBCParam_set
},
{
"rc2-40-cbc",
CIPHER_WEAK,
&asn1_oid_private_rc2_40,
NULL,
EVP_rc2_40_cbc,
CMSRC2CBCParam_get,
CMSRC2CBCParam_set
},
{
"des-ede3-cbc",
0,
ASN1_OID_ID_PKCS3_DES_EDE3_CBC,
NULL,
EVP_des_ede3_cbc,
CMSCBCParam_get,
CMSCBCParam_set
},
{
"des-ede3-cbc",
0,
ASN1_OID_ID_RSADSI_DES_EDE3_CBC,
hx509_crypto_des_rsdi_ede3_cbc,
EVP_des_ede3_cbc,
CMSCBCParam_get,
CMSCBCParam_set
},
{
"aes-128-cbc",
0,
ASN1_OID_ID_AES_128_CBC,
hx509_crypto_aes128_cbc,
EVP_aes_128_cbc,
CMSCBCParam_get,
CMSCBCParam_set
},
{
"aes-192-cbc",
0,
ASN1_OID_ID_AES_192_CBC,
NULL,
EVP_aes_192_cbc,
CMSCBCParam_get,
CMSCBCParam_set
},
{
"aes-256-cbc",
0,
ASN1_OID_ID_AES_256_CBC,
hx509_crypto_aes256_cbc,
EVP_aes_256_cbc,
CMSCBCParam_get,
CMSCBCParam_set
}
};
static const struct hx509cipher *
find_cipher_by_oid(const heim_oid *oid)
{
size_t i;
for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++)
if (der_heim_oid_cmp(oid, ciphers[i].oid) == 0)
return &ciphers[i];
return NULL;
}
static const struct hx509cipher *
find_cipher_by_name(const char *name)
{
size_t i;
for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++)
if (strcasecmp(name, ciphers[i].name) == 0)
return &ciphers[i];
return NULL;
}
HX509_LIB_FUNCTION const heim_oid * HX509_LIB_CALL
hx509_crypto_enctype_by_name(const char *name)
{
const struct hx509cipher *cipher;
cipher = find_cipher_by_name(name);
if (cipher == NULL)
return NULL;
return cipher->oid;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_init(hx509_context context,
const char *provider,
const heim_oid *enctype,
hx509_crypto *crypto)
{
const struct hx509cipher *cipher;
*crypto = NULL;
cipher = find_cipher_by_oid(enctype);
if (cipher == NULL) {
hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
"Algorithm not supported");
return HX509_ALG_NOT_SUPP;
}
*crypto = calloc(1, sizeof(**crypto));
if (*crypto == NULL) {
hx509_clear_error_string(context);
return ENOMEM;
}
(*crypto)->flags = PADDING_PKCS7;
(*crypto)->cipher = cipher;
(*crypto)->c = (*cipher->evp_func)();
if (der_copy_oid(enctype, &(*crypto)->oid)) {
hx509_crypto_destroy(*crypto);
*crypto = NULL;
hx509_clear_error_string(context);
return ENOMEM;
}
return 0;
}
HX509_LIB_FUNCTION const char * HX509_LIB_CALL
hx509_crypto_provider(hx509_crypto crypto)
{
return "unknown";
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
hx509_crypto_destroy(hx509_crypto crypto)
{
if (crypto->name)
free(crypto->name);
if (crypto->key.data)
free(crypto->key.data);
if (crypto->param)
free(crypto->param);
der_free_oid(&crypto->oid);
memset(crypto, 0, sizeof(*crypto));
free(crypto);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_set_key_name(hx509_crypto crypto, const char *name)
{
return 0;
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
hx509_crypto_allow_weak(hx509_crypto crypto)
{
crypto->flags |= ALLOW_WEAK;
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
hx509_crypto_set_padding(hx509_crypto crypto, int padding_type)
{
switch (padding_type) {
case HX509_CRYPTO_PADDING_PKCS7:
crypto->flags &= ~PADDING_FLAGS;
crypto->flags |= PADDING_PKCS7;
break;
case HX509_CRYPTO_PADDING_NONE:
crypto->flags &= ~PADDING_FLAGS;
crypto->flags |= PADDING_NONE;
break;
default:
_hx509_abort("Invalid padding");
}
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_set_key_data(hx509_crypto crypto, const void *data, size_t length)
{
if (EVP_CIPHER_key_length(crypto->c) > (int)length)
return HX509_CRYPTO_INTERNAL_ERROR;
if (crypto->key.data) {
free(crypto->key.data);
crypto->key.data = NULL;
crypto->key.length = 0;
}
crypto->key.data = malloc(length);
if (crypto->key.data == NULL)
return ENOMEM;
memcpy(crypto->key.data, data, length);
crypto->key.length = length;
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_set_random_key(hx509_crypto crypto, heim_octet_string *key)
{
if (crypto->key.data) {
free(crypto->key.data);
crypto->key.length = 0;
}
crypto->key.length = EVP_CIPHER_key_length(crypto->c);
crypto->key.data = malloc(crypto->key.length);
if (crypto->key.data == NULL) {
crypto->key.length = 0;
return ENOMEM;
}
if (RAND_bytes(crypto->key.data, crypto->key.length) <= 0) {
free(crypto->key.data);
crypto->key.data = NULL;
crypto->key.length = 0;
return HX509_CRYPTO_INTERNAL_ERROR;
}
if (key)
return der_copy_octet_string(&crypto->key, key);
else
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_set_params(hx509_context context,
hx509_crypto crypto,
const heim_octet_string *param,
heim_octet_string *ivec)
{
return (*crypto->cipher->set_params)(context, param, crypto, ivec);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_get_params(hx509_context context,
hx509_crypto crypto,
const heim_octet_string *ivec,
heim_octet_string *param)
{
return (*crypto->cipher->get_params)(context, crypto, ivec, param);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_random_iv(hx509_crypto crypto, heim_octet_string *ivec)
{
ivec->length = EVP_CIPHER_iv_length(crypto->c);
ivec->data = malloc(ivec->length);
if (ivec->data == NULL) {
ivec->length = 0;
return ENOMEM;
}
if (RAND_bytes(ivec->data, ivec->length) <= 0) {
free(ivec->data);
ivec->data = NULL;
ivec->length = 0;
return HX509_CRYPTO_INTERNAL_ERROR;
}
return 0;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_encrypt(hx509_crypto crypto,
const void *data,
const size_t length,
const heim_octet_string *ivec,
heim_octet_string **ciphertext)
{
EVP_CIPHER_CTX evp;
size_t padsize, bsize;
int ret;
*ciphertext = NULL;
if ((crypto->cipher->flags & CIPHER_WEAK) &&
(crypto->flags & ALLOW_WEAK) == 0)
return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
assert(EVP_CIPHER_iv_length(crypto->c) == (int)ivec->length);
EVP_CIPHER_CTX_init(&evp);
ret = EVP_CipherInit_ex(&evp, crypto->c, NULL,
crypto->key.data, ivec->data, 1);
if (ret != 1) {
EVP_CIPHER_CTX_cleanup(&evp);
ret = HX509_CRYPTO_INTERNAL_ERROR;
goto out;
}
*ciphertext = calloc(1, sizeof(**ciphertext));
if (*ciphertext == NULL) {
ret = ENOMEM;
goto out;
}
assert(crypto->flags & PADDING_FLAGS);
bsize = EVP_CIPHER_block_size(crypto->c);
padsize = 0;
if (crypto->flags & PADDING_NONE) {
if (bsize != 1 && (length % bsize) != 0)
return HX509_CMS_PADDING_ERROR;
} else if (crypto->flags & PADDING_PKCS7) {
if (bsize != 1)
padsize = bsize - (length % bsize);
}
(*ciphertext)->length = length + padsize;
(*ciphertext)->data = malloc(length + padsize);
if ((*ciphertext)->data == NULL) {
ret = ENOMEM;
goto out;
}
memcpy((*ciphertext)->data, data, length);
if (padsize) {
size_t i;
unsigned char *p = (*ciphertext)->data;
p += length;
for (i = 0; i < padsize; i++)
*p++ = padsize;
}
ret = EVP_Cipher(&evp, (*ciphertext)->data,
(*ciphertext)->data,
length + padsize);
if (ret != 1) {
ret = HX509_CRYPTO_INTERNAL_ERROR;
goto out;
}
ret = 0;
out:
if (ret) {
if (*ciphertext) {
if ((*ciphertext)->data) {
free((*ciphertext)->data);
}
free(*ciphertext);
*ciphertext = NULL;
}
}
EVP_CIPHER_CTX_cleanup(&evp);
return ret;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_decrypt(hx509_crypto crypto,
const void *data,
const size_t length,
heim_octet_string *ivec,
heim_octet_string *clear)
{
EVP_CIPHER_CTX evp;
void *idata = NULL;
int ret;
clear->data = NULL;
clear->length = 0;
if ((crypto->cipher->flags & CIPHER_WEAK) &&
(crypto->flags & ALLOW_WEAK) == 0)
return HX509_CRYPTO_ALGORITHM_BEST_BEFORE;
if (ivec && EVP_CIPHER_iv_length(crypto->c) < (int)ivec->length)
return HX509_CRYPTO_INTERNAL_ERROR;
if (crypto->key.data == NULL)
return HX509_CRYPTO_INTERNAL_ERROR;
if (ivec)
idata = ivec->data;
EVP_CIPHER_CTX_init(&evp);
ret = EVP_CipherInit_ex(&evp, crypto->c, NULL,
crypto->key.data, idata, 0);
if (ret != 1) {
EVP_CIPHER_CTX_cleanup(&evp);
return HX509_CRYPTO_INTERNAL_ERROR;
}
clear->length = length;
clear->data = malloc(length);
if (clear->data == NULL) {
EVP_CIPHER_CTX_cleanup(&evp);
clear->length = 0;
return ENOMEM;
}
if (EVP_Cipher(&evp, clear->data, data, length) != 1) {
return HX509_CRYPTO_INTERNAL_ERROR;
}
EVP_CIPHER_CTX_cleanup(&evp);
if ((crypto->flags & PADDING_PKCS7) && EVP_CIPHER_block_size(crypto->c) > 1) {
int padsize;
unsigned char *p;
int j, bsize = EVP_CIPHER_block_size(crypto->c);
if ((int)clear->length < bsize) {
ret = HX509_CMS_PADDING_ERROR;
goto out;
}
p = clear->data;
p += clear->length - 1;
padsize = *p;
if (padsize > bsize) {
ret = HX509_CMS_PADDING_ERROR;
goto out;
}
clear->length -= padsize;
for (j = 0; j < padsize; j++) {
if (*p-- != padsize) {
ret = HX509_CMS_PADDING_ERROR;
goto out;
}
}
}
return 0;
out:
if (clear->data)
free(clear->data);
clear->data = NULL;
clear->length = 0;
return ret;
}
typedef int (*PBE_string2key_func)(hx509_context,
const char *,
const heim_octet_string *,
hx509_crypto *, heim_octet_string *,
heim_octet_string *,
const heim_oid *, const EVP_MD *);
static int
PBE_string2key(hx509_context context,
const char *password,
const heim_octet_string *parameters,
hx509_crypto *crypto,
heim_octet_string *key, heim_octet_string *iv,
const heim_oid *enc_oid,
const EVP_MD *md)
{
PKCS12_PBEParams p12params;
int passwordlen;
hx509_crypto c;
int iter, saltlen, ret;
unsigned char *salt;
passwordlen = password ? strlen(password) : 0;
if (parameters == NULL)
return HX509_ALG_NOT_SUPP;
ret = decode_PKCS12_PBEParams(parameters->data,
parameters->length,
&p12params, NULL);
if (ret)
goto out;
if (p12params.iterations)
iter = *p12params.iterations;
else
iter = 1;
salt = p12params.salt.data;
saltlen = p12params.salt.length;
if (!PKCS12_key_gen (password, passwordlen, salt, saltlen,
PKCS12_KEY_ID, iter, key->length, key->data, md)) {
ret = HX509_CRYPTO_INTERNAL_ERROR;
goto out;
}
if (!PKCS12_key_gen (password, passwordlen, salt, saltlen,
PKCS12_IV_ID, iter, iv->length, iv->data, md)) {
ret = HX509_CRYPTO_INTERNAL_ERROR;
goto out;
}
ret = hx509_crypto_init(context, NULL, enc_oid, &c);
if (ret)
goto out;
hx509_crypto_allow_weak(c);
ret = hx509_crypto_set_key_data(c, key->data, key->length);
if (ret) {
hx509_crypto_destroy(c);
goto out;
}
*crypto = c;
out:
free_PKCS12_PBEParams(&p12params);
return ret;
}
static const heim_oid *
find_string2key(const heim_oid *oid,
const EVP_CIPHER **c,
const EVP_MD **md,
PBE_string2key_func *s2k)
{
if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC2_CBC) == 0) {
*c = EVP_rc2_40_cbc();
if (*c == NULL)
return NULL;
*md = EVP_sha1();
if (*md == NULL)
return NULL;
*s2k = PBE_string2key;
return &asn1_oid_private_rc2_40;
} else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC2_CBC) == 0) {
*c = EVP_rc2_cbc();
if (*c == NULL)
return NULL;
*md = EVP_sha1();
if (*md == NULL)
return NULL;
*s2k = PBE_string2key;
return ASN1_OID_ID_PKCS3_RC2_CBC;
#if 0
} else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC4) == 0) {
*c = EVP_rc4_40();
if (*c == NULL)
return NULL;
*md = EVP_sha1();
if (*md == NULL)
return NULL;
*s2k = PBE_string2key;
return NULL;
} else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC4) == 0) {
*c = EVP_rc4();
if (*c == NULL)
return NULL;
*md = EVP_sha1();
if (*md == NULL)
return NULL;
*s2k = PBE_string2key;
return ASN1_OID_ID_PKCS3_RC4;
#endif
} else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND3_KEYTRIPLEDES_CBC) == 0) {
*c = EVP_des_ede3_cbc();
if (*c == NULL)
return NULL;
*md = EVP_sha1();
if (*md == NULL)
return NULL;
*s2k = PBE_string2key;
return ASN1_OID_ID_PKCS3_DES_EDE3_CBC;
}
return NULL;
}
/*
*
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_pbe_encrypt(hx509_context context,
hx509_lock lock,
const AlgorithmIdentifier *ai,
const heim_octet_string *content,
heim_octet_string *econtent)
{
hx509_clear_error_string(context);
return EINVAL;
}
/*
*
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_pbe_decrypt(hx509_context context,
hx509_lock lock,
const AlgorithmIdentifier *ai,
const heim_octet_string *econtent,
heim_octet_string *content)
{
const struct _hx509_password *pw;
heim_octet_string key, iv;
const heim_oid *enc_oid;
const EVP_CIPHER *c;
const EVP_MD *md;
PBE_string2key_func s2k;
int ret = 0;
size_t i;
memset(&key, 0, sizeof(key));
memset(&iv, 0, sizeof(iv));
memset(content, 0, sizeof(*content));
enc_oid = find_string2key(&ai->algorithm, &c, &md, &s2k);
if (enc_oid == NULL) {
hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
"String to key algorithm not supported");
ret = HX509_ALG_NOT_SUPP;
goto out;
}
key.length = EVP_CIPHER_key_length(c);
key.data = malloc(key.length);
if (key.data == NULL) {
ret = ENOMEM;
hx509_clear_error_string(context);
goto out;
}
iv.length = EVP_CIPHER_iv_length(c);
iv.data = malloc(iv.length);
if (iv.data == NULL) {
ret = ENOMEM;
hx509_clear_error_string(context);
goto out;
}
pw = _hx509_lock_get_passwords(lock);
ret = HX509_CRYPTO_INTERNAL_ERROR;
for (i = 0; i < pw->len + 1; i++) {
hx509_crypto crypto;
const char *password;
if (i < pw->len)
password = pw->val[i];
else if (i < pw->len + 1)
password = "";
else
password = NULL;
ret = (*s2k)(context, password, ai->parameters, &crypto,
&key, &iv, enc_oid, md);
if (ret)
goto out;
ret = hx509_crypto_decrypt(crypto,
econtent->data,
econtent->length,
&iv,
content);
hx509_crypto_destroy(crypto);
if (ret == 0)
goto out;
}
out:
if (key.data)
der_free_octet_string(&key);
if (iv.data)
der_free_octet_string(&iv);
return ret;
}
/*
*
*/
static int
match_keys_rsa(hx509_cert c, hx509_private_key private_key)
{
const Certificate *cert;
const SubjectPublicKeyInfo *spi;
RSAPublicKey pk;
RSA *rsa;
size_t size;
int ret;
if (private_key->private_key.rsa == NULL)
return 0;
rsa = private_key->private_key.rsa;
if (rsa->d == NULL || rsa->p == NULL || rsa->q == NULL)
return 0;
cert = _hx509_get_cert(c);
spi = &cert->tbsCertificate.subjectPublicKeyInfo;
rsa = RSA_new();
if (rsa == NULL)
return 0;
ret = decode_RSAPublicKey(spi->subjectPublicKey.data,
spi->subjectPublicKey.length / 8,
&pk, &size);
if (ret) {
RSA_free(rsa);
return 0;
}
rsa->n = heim_int2BN(&pk.modulus);
rsa->e = heim_int2BN(&pk.publicExponent);
free_RSAPublicKey(&pk);
rsa->d = BN_dup(private_key->private_key.rsa->d);
rsa->p = BN_dup(private_key->private_key.rsa->p);
rsa->q = BN_dup(private_key->private_key.rsa->q);
rsa->dmp1 = BN_dup(private_key->private_key.rsa->dmp1);
rsa->dmq1 = BN_dup(private_key->private_key.rsa->dmq1);
rsa->iqmp = BN_dup(private_key->private_key.rsa->iqmp);
if (rsa->n == NULL || rsa->e == NULL ||
rsa->d == NULL || rsa->p == NULL|| rsa->q == NULL ||
rsa->dmp1 == NULL || rsa->dmq1 == NULL) {
RSA_free(rsa);
return 0;
}
ret = RSA_check_key(rsa);
RSA_free(rsa);
return ret == 1;
}
static int
match_keys_ec(hx509_cert c, hx509_private_key private_key)
{
return 1; /* XXX use EC_KEY_check_key */
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
_hx509_match_keys(hx509_cert c, hx509_private_key key)
{
if (!key->ops)
return 0;
if (der_heim_oid_cmp(key->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0)
return match_keys_rsa(c, key);
if (der_heim_oid_cmp(key->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) == 0)
return match_keys_ec(c, key);
return 0;
}
static const heim_oid *
find_keytype(const hx509_private_key key)
{
const struct signature_alg *md;
if (key == NULL)
return NULL;
md = _hx509_find_sig_alg(key->signature_alg);
if (md == NULL)
return NULL;
return md->key_oid;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_select(const hx509_context context,
int type,
const hx509_private_key source,
hx509_peer_info peer,
AlgorithmIdentifier *selected)
{
const AlgorithmIdentifier *def = NULL;
size_t i, j;
int ret, bits;
memset(selected, 0, sizeof(*selected));
if (type == HX509_SELECT_DIGEST) {
bits = SIG_DIGEST;
if (source)
def = alg_for_privatekey(source, type);
if (def == NULL)
def = _hx509_crypto_default_digest_alg;
} else if (type == HX509_SELECT_PUBLIC_SIG) {
bits = SIG_PUBLIC_SIG;
/* XXX depend on `source´ and `peer´ */
if (source)
def = alg_for_privatekey(source, type);
if (def == NULL)
def = _hx509_crypto_default_sig_alg;
} else if (type == HX509_SELECT_SECRET_ENC) {
bits = SIG_SECRET;
def = _hx509_crypto_default_secret_alg;
} else {
hx509_set_error_string(context, 0, EINVAL,
"Unknown type %d of selection", type);
return EINVAL;
}
if (peer) {
const heim_oid *keytype = NULL;
keytype = find_keytype(source);
for (i = 0; i < peer->len; i++) {
for (j = 0; sig_algs[j]; j++) {
if ((sig_algs[j]->flags & bits) != bits)
continue;
if (der_heim_oid_cmp(sig_algs[j]->sig_oid,
&peer->val[i].algorithm) != 0)
continue;
if (keytype && sig_algs[j]->key_oid &&
der_heim_oid_cmp(keytype, sig_algs[j]->key_oid))
continue;
/* found one, use that */
ret = copy_AlgorithmIdentifier(&peer->val[i], selected);
if (ret)
hx509_clear_error_string(context);
return ret;
}
if (bits & SIG_SECRET) {
const struct hx509cipher *cipher;
cipher = find_cipher_by_oid(&peer->val[i].algorithm);
if (cipher == NULL)
continue;
if (cipher->ai_func == NULL)
continue;
ret = copy_AlgorithmIdentifier(cipher->ai_func(), selected);
if (ret)
hx509_clear_error_string(context);
return ret;
}
}
}
/* use default */
ret = copy_AlgorithmIdentifier(def, selected);
if (ret)
hx509_clear_error_string(context);
return ret;
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_crypto_available(hx509_context context,
int type,
hx509_cert source,
AlgorithmIdentifier **val,
unsigned int *plen)
{
const heim_oid *keytype = NULL;
unsigned int len, i;
void *ptr;
int bits, ret;
*val = NULL;
if (type == HX509_SELECT_ALL) {
bits = SIG_DIGEST | SIG_PUBLIC_SIG | SIG_SECRET;
} else if (type == HX509_SELECT_DIGEST) {
bits = SIG_DIGEST;
} else if (type == HX509_SELECT_PUBLIC_SIG) {
bits = SIG_PUBLIC_SIG;
} else {
hx509_set_error_string(context, 0, EINVAL,
"Unknown type %d of available", type);
return EINVAL;
}
if (source)
keytype = find_keytype(_hx509_cert_private_key(source));
len = 0;
for (i = 0; sig_algs[i]; i++) {
if ((sig_algs[i]->flags & bits) == 0)
continue;
if (sig_algs[i]->sig_alg == NULL)
continue;
if (keytype && sig_algs[i]->key_oid &&
der_heim_oid_cmp(sig_algs[i]->key_oid, keytype))
continue;
/* found one, add that to the list */
ptr = realloc(*val, sizeof(**val) * (len + 1));
if (ptr == NULL)
goto out;
*val = ptr;
ret = copy_AlgorithmIdentifier(sig_algs[i]->sig_alg, &(*val)[len]);
if (ret)
goto out;
len++;
}
/* Add AES */
if (bits & SIG_SECRET) {
for (i = 0; i < sizeof(ciphers)/sizeof(ciphers[0]); i++) {
if (ciphers[i].flags & CIPHER_WEAK)
continue;
if (ciphers[i].ai_func == NULL)
continue;
ptr = realloc(*val, sizeof(**val) * (len + 1));
if (ptr == NULL)
goto out;
*val = ptr;
ret = copy_AlgorithmIdentifier((ciphers[i].ai_func)(), &(*val)[len]);
if (ret)
goto out;
len++;
}
}
*plen = len;
return 0;
out:
for (i = 0; i < len; i++)
free_AlgorithmIdentifier(&(*val)[i]);
free(*val);
*val = NULL;
hx509_set_error_string(context, 0, ENOMEM, "out of memory");
return ENOMEM;
}
HX509_LIB_FUNCTION void HX509_LIB_CALL
hx509_crypto_free_algs(AlgorithmIdentifier *val,
unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
free_AlgorithmIdentifier(&val[i]);
free(val);
}