Parse X.509 certificate, get RSA public key, RSA encrypt
Also add support older (< 3.5.0) GnuTLS versions
This commit is contained in:
parent
166d1bc14d
commit
90fd660803
22
asn.c
22
asn.c
@ -207,7 +207,7 @@ int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uin
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e)
|
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e, int check_pk_algo)
|
||||||
{
|
{
|
||||||
int asn1_rv;
|
int asn1_rv;
|
||||||
asn1_node asn_cert;
|
asn1_node asn_cert;
|
||||||
@ -234,6 +234,26 @@ int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_pk_algo) {
|
||||||
|
/* Get and check cert's public key algorithm */
|
||||||
|
buflen = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", buf, (int *)&buflen))) {
|
||||||
|
logger(Core, Error, "%s:%s:%d Failed to get cert's public key algorithm. Error = 0x%x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, asn1_rv, asn1_strerror(asn1_rv));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strncmp((char *)buf, OID_SHA_WITH_RSA_SIGNATURE, strlen(OID_SHA_WITH_RSA_SIGNATURE)) != 0)
|
||||||
|
&& (strncmp((char *)buf, OID_MD5_WITH_RSA_SIGNATURE, strlen(OID_MD5_WITH_RSA_SIGNATURE)) != 0)) {
|
||||||
|
|
||||||
|
logger(Core, Error, "%s:%s:%d Wrong public key algorithm: %s\n",
|
||||||
|
__FILE__, __func__, __LINE__, buf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buflen = sizeof(buf) - 1;
|
buflen = sizeof(buf) - 1;
|
||||||
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
|
if (ASN1_SUCCESS != (asn1_rv = asn1_read_value(asn_cert, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", buf, &buflen))) {
|
||||||
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
|
logger(Core, Error, "%s:%s:%d Failed to get cert's public key. Error = 0x%x (%s)\n",
|
||||||
|
4
asn.h
4
asn.h
@ -29,10 +29,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define OID_SHA_WITH_RSA_SIGNATURE "1.3.14.3.2.15"
|
||||||
|
#define OID_MD5_WITH_RSA_SIGNATURE "1.3.14.3.2.25"
|
||||||
|
|
||||||
int init_asn1_lib(void);
|
int init_asn1_lib(void);
|
||||||
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
|
int write_pkcs1_der_pubkey(const gnutls_datum_t *m, const gnutls_datum_t *e, uint8_t *out, int *out_len);
|
||||||
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e);
|
int libtasn_read_cert_pk_parameters(uint8_t *data, size_t len, gnutls_datum_t *m, gnutls_datum_t *e, int check_pk_algo);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
84
configure.ac
84
configure.ac
@ -29,6 +29,9 @@ fi
|
|||||||
|
|
||||||
AC_PATH_TOOL(PKG_CONFIG, pkg-config)
|
AC_PATH_TOOL(PKG_CONFIG, pkg-config)
|
||||||
|
|
||||||
|
# no .pc for GMP
|
||||||
|
AC_SEARCH_LIBS([__gmpz_init], [gmp])
|
||||||
|
|
||||||
AC_SEARCH_LIBS(socket, socket)
|
AC_SEARCH_LIBS(socket, socket)
|
||||||
AC_SEARCH_LIBS(inet_aton, resolv)
|
AC_SEARCH_LIBS(inet_aton, resolv)
|
||||||
|
|
||||||
@ -61,74 +64,6 @@ AC_ARG_ENABLE([address-sanitizer], AS_HELP_STRING([--enable-address-sanitizer],
|
|||||||
[AC_MSG_ERROR([Address Sanitizer not available])])
|
[AC_MSG_ERROR([Address Sanitizer not available])])
|
||||||
])
|
])
|
||||||
|
|
||||||
#
|
|
||||||
# OpenSSL detection borrowed from stunnel
|
|
||||||
#
|
|
||||||
checkssldir() { :
|
|
||||||
if test -f "$1/include/openssl/ssl.h"; then
|
|
||||||
ssldir="$1"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
AC_MSG_CHECKING([for OpenSSL directory])
|
|
||||||
AC_ARG_WITH(openssl,
|
|
||||||
[ --with-openssl=DIR look for OpenSSL at DIR/include, DIR/lib],
|
|
||||||
[
|
|
||||||
dnl Check the specified location only
|
|
||||||
checkssldir "$withval"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
dnl Search default locations of OpenSSL library
|
|
||||||
for maindir in /usr/local /usr/lib /usr/pkg /usr /var/ssl /opt; do
|
|
||||||
for dir in $maindir $maindir/openssl $maindir/ssl; do
|
|
||||||
checkssldir $dir && break 2
|
|
||||||
done
|
|
||||||
done
|
|
||||||
]
|
|
||||||
)
|
|
||||||
if test -z "$ssldir"; then
|
|
||||||
AC_MSG_RESULT([Not found])
|
|
||||||
echo
|
|
||||||
echo "ERROR: Could not find OpenSSL headers/libraries."
|
|
||||||
if test -f /etc/debian_version; then
|
|
||||||
echo "Probably you need to install the libssl-dev package."
|
|
||||||
elif test -f /etc/redhat-release; then
|
|
||||||
echo "Probably you need to install the openssl-devel package."
|
|
||||||
fi
|
|
||||||
echo "To specify a path manually, use the --with-openssl option."
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
AC_MSG_RESULT([$ssldir])
|
|
||||||
AC_SUBST(ssldir)
|
|
||||||
AC_DEFINE_UNQUOTED(ssldir, "$ssldir")
|
|
||||||
|
|
||||||
dnl Add OpenSSL includes and libraries
|
|
||||||
CFLAGS="$CFLAGS -I$ssldir/include"
|
|
||||||
AC_ARG_ENABLE(static-openssl,
|
|
||||||
[ --enable-static-openssl link OpenSSL statically],
|
|
||||||
[static_openssl=yes],
|
|
||||||
[static_openssl=no])
|
|
||||||
if test x"$static_openssl" = "xyes"; then
|
|
||||||
# OpenSSL generally relies on libz
|
|
||||||
AC_SEARCH_LIBS(deflate, z)
|
|
||||||
LIBS="-L$ssldir/lib -L$ssldir/lib64 -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic -ldl $LIBS"
|
|
||||||
else
|
|
||||||
LIBS="-L$ssldir/lib -L$ssldir/lib64 -lssl -lcrypto -ldl $LIBS"
|
|
||||||
|
|
||||||
#
|
|
||||||
# target-specific stuff
|
|
||||||
#
|
|
||||||
case "$host" in
|
|
||||||
*-*-solaris*)
|
|
||||||
LDFLAGS="$LDFLAGS -R$ssldir/lib"
|
|
||||||
;;
|
|
||||||
*-dec-osf*)
|
|
||||||
LDFLAGS="$LDFLAGS -Wl,-rpath,$ssldir/lib"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
dnl CredSSP feature
|
dnl CredSSP feature
|
||||||
AC_ARG_ENABLE([credssp], AS_HELP_STRING([--disable-credssp], [disable support for CredSSP]))
|
AC_ARG_ENABLE([credssp], AS_HELP_STRING([--disable-credssp], [disable support for CredSSP]))
|
||||||
@ -229,6 +164,19 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# hogweed
|
||||||
|
if test -n "$PKG_CONFIG"; then
|
||||||
|
PKG_CHECK_MODULES(HOGWEED, hogweed, [HAVE_HOGWEED=1], [HAVE_HOGWEED=0])
|
||||||
|
fi
|
||||||
|
if test x"$HAVE_HOGWEED" = "x1"; then
|
||||||
|
CFLAGS="$CFLAGS $HOGWEED_CFLAGS"
|
||||||
|
LIBS="$LIBS $HOGWEED_LIBS"
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "rdesktop requires hogweed. Please install the dependency"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# GnuTLS
|
# GnuTLS
|
||||||
if test -n "$PKG_CONFIG"; then
|
if test -n "$PKG_CONFIG"; then
|
||||||
|
293
ssl.c
293
ssl.c
@ -24,23 +24,7 @@
|
|||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
#include "asn.h"
|
#include "asn.h"
|
||||||
|
|
||||||
/* Helper function to log internal SSL errors using logger */
|
#include <gnutls/x509.h>
|
||||||
void
|
|
||||||
rdssl_log_ssl_errors(const char *prefix)
|
|
||||||
{
|
|
||||||
unsigned long err;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
err = ERR_get_error();
|
|
||||||
if (err == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
logger(Protocol, Error,
|
|
||||||
"%s, 0x%.8x:%s:%s: %s",
|
|
||||||
prefix, err, ERR_lib_error_string(err),
|
|
||||||
ERR_func_error_string(err), ERR_reason_error_string(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rdssl_sha1_init(RDSSL_SHA1 * sha1)
|
rdssl_sha1_init(RDSSL_SHA1 * sha1)
|
||||||
@ -108,145 +92,186 @@ void
|
|||||||
rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
|
rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
|
||||||
uint8 * exponent)
|
uint8 * exponent)
|
||||||
{
|
{
|
||||||
BN_CTX *ctx;
|
mpz_t exp, mod;
|
||||||
BIGNUM *mod, *exp, *x, *y;
|
|
||||||
uint8 inr[SEC_MAX_MODULUS_SIZE];
|
|
||||||
int outlen;
|
|
||||||
|
|
||||||
reverse(modulus, modulus_size);
|
mpz_t y;
|
||||||
reverse(exponent, SEC_EXPONENT_SIZE);
|
mpz_t x;
|
||||||
memcpy(inr, in, len);
|
|
||||||
reverse(inr, len);
|
|
||||||
|
|
||||||
ctx = BN_CTX_new();
|
size_t outlen;
|
||||||
mod = BN_new();
|
|
||||||
exp = BN_new();
|
mpz_init(y);
|
||||||
x = BN_new();
|
mpz_init(x);
|
||||||
y = BN_new();
|
mpz_init(exp);
|
||||||
|
mpz_init(mod);
|
||||||
|
|
||||||
|
mpz_import(mod, modulus_size, 1, sizeof(modulus[0]), 0, 0, modulus);
|
||||||
|
// TODO: Need exponent size
|
||||||
|
mpz_import(exp, 3, 1, sizeof(exponent[0]), 0, 0, exponent);
|
||||||
|
|
||||||
|
mpz_import(x, len, -1, sizeof(in[0]), 0, 0, in);
|
||||||
|
|
||||||
|
mpz_powm(y, x, exp, mod);
|
||||||
|
|
||||||
|
mpz_export(out, &outlen, -1, sizeof(out[0]), 0, 0, y);
|
||||||
|
|
||||||
BN_bin2bn(modulus, modulus_size, mod);
|
|
||||||
BN_bin2bn(exponent, SEC_EXPONENT_SIZE, exp);
|
|
||||||
BN_bin2bn(inr, len, x);
|
|
||||||
BN_mod_exp(y, x, exp, mod, ctx);
|
|
||||||
outlen = BN_bn2bin(y, out);
|
|
||||||
reverse(out, outlen);
|
|
||||||
if (outlen < (int) modulus_size)
|
if (outlen < (int) modulus_size)
|
||||||
memset(out + outlen, 0, modulus_size - outlen);
|
memset(out + outlen, 0, modulus_size - outlen);
|
||||||
|
|
||||||
BN_free(y);
|
|
||||||
BN_clear_free(x);
|
|
||||||
BN_free(exp);
|
|
||||||
BN_free(mod);
|
|
||||||
BN_CTX_free(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns newly allocated RDSSL_CERT or NULL */
|
/* returns newly allocated RDSSL_CERT or NULL */
|
||||||
RDSSL_CERT *
|
RDSSL_CERT *
|
||||||
rdssl_cert_read(uint8 * data, uint32 len)
|
rdssl_cert_read(uint8 * data, uint32 len)
|
||||||
{
|
{
|
||||||
/* this will move the data pointer but we don't care, we don't use it again */
|
int ret;
|
||||||
return d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &data, len);
|
gnutls_datum_t cert_data;
|
||||||
|
gnutls_x509_crt_t *cert;
|
||||||
|
|
||||||
|
cert = malloc(sizeof(*cert));
|
||||||
|
|
||||||
|
if (!cert) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to allocate memory for certificate structure.\n",
|
||||||
|
__FILE__, __func__, __LINE__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = gnutls_x509_crt_init(cert)) != GNUTLS_E_SUCCESS) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to init certificate structure. GnuTLS error = 0x%02x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, ret, gnutls_strerror(ret));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_data.size = len;
|
||||||
|
cert_data.data = data;
|
||||||
|
|
||||||
|
if ((ret = gnutls_x509_crt_import(*cert, &cert_data, GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to import DER encoded certificate. GnuTLS error = 0x%02x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, ret, gnutls_strerror(ret));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rdssl_cert_free(RDSSL_CERT * cert)
|
rdssl_cert_free(RDSSL_CERT * cert)
|
||||||
{
|
{
|
||||||
X509_free(cert);
|
gnutls_free(cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AFAIK, there's no way to alter the decoded certificate using GnuTLS.
|
||||||
|
*
|
||||||
|
* Upon detecting "problem" (wrong public RSA key OID) certificate
|
||||||
|
* we basically have two options:
|
||||||
|
*
|
||||||
|
* 1)) encode certificate back to DER, then parse it using libtasn1,
|
||||||
|
* fix public key OID (set it to 1.2.840.113549.1.1.1), encode to DER again
|
||||||
|
* and finally reparse using GnuTLS
|
||||||
|
*
|
||||||
|
* 2) encode cert back to DER, get RSA public key parameters using libtasn1
|
||||||
|
*
|
||||||
|
* Or can rewrite the whole certificate related stuff later.
|
||||||
|
*/
|
||||||
|
|
||||||
/* returns newly allocated RDSSL_RKEY or NULL */
|
/* returns newly allocated RDSSL_RKEY or NULL */
|
||||||
RDSSL_RKEY *
|
RDSSL_RKEY *
|
||||||
rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len)
|
rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len)
|
||||||
{
|
{
|
||||||
EVP_PKEY *epk = NULL;
|
|
||||||
RDSSL_RKEY *lkey;
|
|
||||||
int nid;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
int check_pk_algo;
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
RDSSL_RKEY *pkey;
|
||||||
const unsigned char *p;
|
gnutls_datum_t m, e;
|
||||||
RSA *rsa = NULL;
|
|
||||||
int pklen;
|
unsigned int algo, bits;
|
||||||
#endif
|
char oid[64];
|
||||||
|
size_t oid_size = sizeof(oid);
|
||||||
|
|
||||||
|
uint8_t data[2048];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
check_pk_algo = 1;
|
||||||
|
|
||||||
|
algo = gnutls_x509_crt_get_pk_algorithm(*cert, &bits);
|
||||||
|
|
||||||
/* By some reason, Microsoft sets the OID of the Public RSA key to
|
/* By some reason, Microsoft sets the OID of the Public RSA key to
|
||||||
the oid for "MD5 with RSA Encryption" instead of "RSA Encryption"
|
the oid for "MD5 with RSA Encryption" instead of "RSA Encryption"
|
||||||
|
|
||||||
Kudos to Richard Levitte for the following (. intuitive .)
|
Kudos to Richard Levitte for the finding this and proposed the fix
|
||||||
lines of code that resets the OID and let's us extract the key. */
|
using OpenSSL. */
|
||||||
|
|
||||||
X509_PUBKEY *key = NULL;
|
if (algo == GNUTLS_PK_RSA) {
|
||||||
X509_ALGOR *algor = NULL;
|
|
||||||
|
|
||||||
key = X509_get_X509_PUBKEY(cert);
|
|
||||||
if (key == NULL)
|
|
||||||
{
|
|
||||||
logger(Protocol, Error,
|
|
||||||
"rdssl_cert_to_key(), failed to get public key from certificate");
|
|
||||||
rdssl_log_ssl_errors("rdssl_cert_to_key()");
|
|
||||||
|
|
||||||
|
if ((ret = gnutls_x509_crt_get_pk_rsa_raw(*cert, &m, &e)) != GNUTLS_E_SUCCESS) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to get RSA public key parameters from certificate. GnuTLS error = 0x%02x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, ret, gnutls_strerror(ret));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = X509_PUBKEY_get0_param(NULL, NULL, 0, &algor, key);
|
} else if (algo == GNUTLS_E_UNIMPLEMENTED_FEATURE) {
|
||||||
if (ret != 1)
|
|
||||||
{
|
|
||||||
logger(Protocol, Error,
|
|
||||||
"rdssl_cert_to_key(), failed to get algorithm used for public key");
|
|
||||||
rdssl_log_ssl_errors("rdssl_cert_to_key()");
|
|
||||||
|
|
||||||
|
/* Maybe we should get rid of gnutls_x509_crt_get_pk_oid() and
|
||||||
|
check public key algo in libtasn_read_cert_pk_params() */
|
||||||
|
|
||||||
|
#if GNUTLS_VERSION_NUMBER >= 0x030500
|
||||||
|
// manpage says that this function is useful when gnutls_x509_crt_get_pk_algorithm() returns GNUTLS_PK_UNKNOWN
|
||||||
|
if ((ret = gnutls_x509_crt_get_pk_oid(*cert, oid, &oid_size)) != GNUTLS_E_SUCCESS) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to get OID of public key algorithm. GnuTLS error = 0x%02x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, ret, gnutls_strerror(ret));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nid = OBJ_obj2nid(algor->algorithm);
|
if (!strncmp(oid, OID_SHA_WITH_RSA_SIGNATURE, strlen(OID_SHA_WITH_RSA_SIGNATURE))
|
||||||
|
|| !strncmp(oid, OID_MD5_WITH_RSA_SIGNATURE, strlen(OID_MD5_WITH_RSA_SIGNATURE))) {
|
||||||
if ((nid == NID_md5WithRSAEncryption) || (nid == NID_shaWithRSAEncryption))
|
check_pk_algo = 0;
|
||||||
{
|
} else {
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
logger(Protocol, Error, "%s:%s:%d: Wrong public key algorithm algo = 0x%02x (%s)\n",
|
||||||
logger(Protocol, Debug,
|
__FILE__, __func__, __LINE__, algo, oid);
|
||||||
"rdssl_cert_to_key(), re-setting algorithm type to RSA in server certificate");
|
|
||||||
X509_PUBKEY_set0_param(key, OBJ_nid2obj(NID_rsaEncryption), 0, NULL, NULL, 0);
|
|
||||||
#else
|
|
||||||
|
|
||||||
if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, key))
|
|
||||||
{
|
|
||||||
logger(Protocol, Error,
|
|
||||||
"rdssl_cert_to_key(), failed to get algorithm used for public key");
|
|
||||||
rdssl_log_ssl_errors("rdssl_cert_to_key()");
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(rsa = d2i_RSAPublicKey(NULL, &p, pklen)))
|
|
||||||
{
|
|
||||||
logger(Protocol, Error,
|
|
||||||
"rdssl_cert_to_key(), failed to extract public key from certificate");
|
|
||||||
rdssl_log_ssl_errors("rdssl_cert_to_key()");
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lkey = RSAPublicKey_dup(rsa);
|
|
||||||
*key_len = RSA_size(lkey);
|
|
||||||
return lkey;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
len = sizeof(data);
|
||||||
|
|
||||||
|
if ((ret = gnutls_x509_crt_export(*cert, GNUTLS_X509_FMT_DER, data, &len)) != GNUTLS_E_SUCCESS) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to encode X.509 certificate to DER. GnuTLS error = 0x%02x (%s)\n",
|
||||||
|
__FILE__, __func__, __LINE__, ret, gnutls_strerror(ret));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
epk = X509_get_pubkey(cert);
|
if ((ret = libtasn_read_cert_pk_parameters(data, len, &m, &e, check_pk_algo)) != 0) {
|
||||||
if (NULL == epk)
|
logger(Protocol, Error, "%s:%s:%d: Failed to read RSA public key parameters\n",
|
||||||
{
|
__FILE__, __func__, __LINE__);
|
||||||
logger(Protocol, Error,
|
|
||||||
"rdssl_cert_to_key(), failed to extract public key from certificate");
|
|
||||||
rdssl_log_ssl_errors("rdssl_cert_to_key()");
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
lkey = RSAPublicKey_dup(EVP_PKEY_get1_RSA(epk));
|
} else {
|
||||||
EVP_PKEY_free(epk);
|
logger(Protocol, Error, "%s:%s:%d: Failed to get public key algorithm from certificate. algo = 0x%02x (%d)\n",
|
||||||
*key_len = RSA_size(lkey);
|
__FILE__, __func__, __LINE__, algo, algo);
|
||||||
return lkey;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = malloc(sizeof(*pkey));
|
||||||
|
|
||||||
|
if (!pkey) {
|
||||||
|
logger(Protocol, Error, "%s:%s:%d: Failed to allocate memory for RSA public key\n",
|
||||||
|
__FILE__, __func__, __LINE__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsa_public_key_init(pkey);
|
||||||
|
|
||||||
|
mpz_import(pkey->n, m.size, 1, sizeof(m.data[0]), 0, 0, m.data);
|
||||||
|
mpz_import(pkey->e, e.size, 1, sizeof(e.data[0]), 0, 0, e.data);
|
||||||
|
|
||||||
|
rsa_public_key_prepare(pkey);
|
||||||
|
|
||||||
|
*key_len = pkey->size;
|
||||||
|
|
||||||
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns boolean */
|
/* returns boolean */
|
||||||
@ -270,40 +295,52 @@ rdssl_certs_ok(RDSSL_CERT * server_cert, RDSSL_CERT * cacert)
|
|||||||
int
|
int
|
||||||
rdssl_cert_print_fp(FILE * fp, RDSSL_CERT * cert)
|
rdssl_cert_print_fp(FILE * fp, RDSSL_CERT * cert)
|
||||||
{
|
{
|
||||||
return X509_print_fp(fp, cert);
|
int ret;
|
||||||
|
gnutls_datum_t cinfo;
|
||||||
|
|
||||||
|
ret = gnutls_x509_crt_print(*cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
fprintf (fp, "\t%s\n", cinfo.data);
|
||||||
|
gnutls_free(cinfo.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rdssl_rkey_free(RDSSL_RKEY * rkey)
|
rdssl_rkey_free(RDSSL_RKEY * rkey)
|
||||||
{
|
{
|
||||||
RSA_free(rkey);
|
rsa_public_key_clear(rkey);
|
||||||
|
free(rkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Actually we can get rid of this function and use rsa_public)_key in rdssl_rsa_encrypt */
|
||||||
/* returns error */
|
/* returns error */
|
||||||
int
|
int
|
||||||
rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus,
|
rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus,
|
||||||
uint32 max_mod_len)
|
uint32 max_mod_len)
|
||||||
{
|
{
|
||||||
int len;
|
size_t outlen;
|
||||||
|
|
||||||
BIGNUM *e = NULL;
|
// TODO: Check size before exporing
|
||||||
BIGNUM *n = NULL;
|
mpz_export(modulus, &outlen, 1, sizeof(uint8), 0, 0, rkey->n);
|
||||||
|
mpz_export(exponent, &outlen, 1, sizeof(uint8), 0, 0, rkey->e);
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
/*
|
||||||
e = rkey->e;
|
* Note that gnutls_x509_crt_get_pk_rsa_raw() exports modulus with additional
|
||||||
n = rkey->n;
|
* zero byte as signed bignum. We can easily import this value using mpz_import()
|
||||||
#else
|
* After we use mpz_export() on pkey.n (modulus) it will (according to GMP docs)
|
||||||
RSA_get0_key(rkey, &n, &e, NULL);
|
* export data without sign byte.
|
||||||
#endif
|
*
|
||||||
|
* This is only important if you get modulus from certificate using GnuTLS,
|
||||||
|
* save it somewhere, import it into mpz and then export it from the said mpz to some
|
||||||
|
* buffer. If you then compare initiail (saved) modulus with newly exported one they
|
||||||
|
* will be different.
|
||||||
|
*
|
||||||
|
* On the other hand if we use mpz_t all the way, there will be no such situation.
|
||||||
|
*/
|
||||||
|
|
||||||
if ((BN_num_bytes(e) > (int) max_exp_len) || (BN_num_bytes(n) > (int) max_mod_len))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
len = BN_bn2bin(e, exponent);
|
|
||||||
reverse(exponent, len);
|
|
||||||
len = BN_bn2bin(n, modulus);
|
|
||||||
reverse(modulus, len);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
ssl.h
17
ssl.h
@ -23,26 +23,19 @@
|
|||||||
#ifndef _RDSSL_H
|
#ifndef _RDSSL_H
|
||||||
#define _RDSSL_H
|
#define _RDSSL_H
|
||||||
|
|
||||||
#include <openssl/err.h>
|
|
||||||
#include <openssl/bn.h>
|
|
||||||
#include <openssl/x509v3.h>
|
|
||||||
|
|
||||||
#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f)
|
|
||||||
#define D2I_X509_CONST const
|
|
||||||
#else
|
|
||||||
#define D2I_X509_CONST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <nettle/md5.h>
|
#include <nettle/md5.h>
|
||||||
#include <nettle/sha1.h>
|
#include <nettle/sha1.h>
|
||||||
#include <nettle/arcfour.h>
|
#include <nettle/arcfour.h>
|
||||||
#include <nettle/hmac.h>
|
#include <nettle/hmac.h>
|
||||||
|
#include <nettle/rsa.h>
|
||||||
|
|
||||||
|
#include <gnutls/x509.h>
|
||||||
|
|
||||||
#define RDSSL_RC4 struct arcfour_ctx
|
#define RDSSL_RC4 struct arcfour_ctx
|
||||||
#define RDSSL_SHA1 struct sha1_ctx
|
#define RDSSL_SHA1 struct sha1_ctx
|
||||||
#define RDSSL_MD5 struct md5_ctx
|
#define RDSSL_MD5 struct md5_ctx
|
||||||
#define RDSSL_CERT X509
|
#define RDSSL_CERT gnutls_x509_crt_t
|
||||||
#define RDSSL_RKEY RSA
|
#define RDSSL_RKEY struct rsa_public_key
|
||||||
|
|
||||||
void rdssl_sha1_init(RDSSL_SHA1 * sha1);
|
void rdssl_sha1_init(RDSSL_SHA1 * sha1);
|
||||||
void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len);
|
void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len);
|
||||||
|
Loading…
Reference in New Issue
Block a user