Setting Certificate/Private Key Improvements (#25)
Add tls_set_certificate_pem() and tls_set_certificate_der() functions for setting certificate and private key on a TLS context in respective formats. Private key may optionally be passed as a separate argument, or part of the certificate data.
This commit is contained in:
parent
a627951aeb
commit
1ff344dbd9
2 changed files with 140 additions and 21 deletions
|
@ -24,11 +24,21 @@ enum tls_fingerprint {
|
|||
TLS_FINGERPRINT_SHA256,
|
||||
};
|
||||
|
||||
enum tls_keytype {
|
||||
TLS_KEYTYPE_RSA,
|
||||
TLS_KEYTYPE_EC,
|
||||
};
|
||||
|
||||
|
||||
int tls_alloc(struct tls **tlsp, enum tls_method method, const char *keyfile,
|
||||
const char *pwd);
|
||||
int tls_add_ca(struct tls *tls, const char *capath);
|
||||
int tls_set_selfsigned(struct tls *tls, const char *cn);
|
||||
int tls_set_certificate_pem(struct tls *tls, const char *cert, size_t len_cert,
|
||||
const char *key, size_t len_key);
|
||||
int tls_set_certificate_der(struct tls *tls, enum tls_keytype key_type,
|
||||
const uint8_t *cert, size_t len_cert, const uint8_t *key,
|
||||
size_t len_key);
|
||||
int tls_set_certificate(struct tls *tls, const char *cert, size_t len);
|
||||
void tls_set_verify_client(struct tls *tls);
|
||||
int tls_set_srtp(struct tls *tls, const char *suites);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <re_types.h>
|
||||
#include <re_fmt.h>
|
||||
#include <re_mem.h>
|
||||
|
@ -72,6 +74,19 @@ static int password_cb(char *buf, int size, int rwflag, void *userdata)
|
|||
}
|
||||
|
||||
|
||||
static int keytype2int(enum tls_keytype type)
|
||||
{
|
||||
switch (type) {
|
||||
case TLS_KEYTYPE_EC:
|
||||
return EVP_PKEY_EC;
|
||||
case TLS_KEYTYPE_RSA:
|
||||
return EVP_PKEY_RSA;
|
||||
default:
|
||||
return EVP_PKEY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new TLS context
|
||||
*
|
||||
|
@ -337,55 +352,63 @@ int tls_set_selfsigned(struct tls *tls, const char *cn)
|
|||
/**
|
||||
* Set the certificate and private key on a TLS context
|
||||
*
|
||||
* @param tls TLS Context
|
||||
* @param pem Certificate and private key in PEM format
|
||||
* @param len Length of PEM string
|
||||
* @param tls TLS Context
|
||||
* @param cert Certificate in PEM format
|
||||
* @param len_cert Length of certificate PEM string
|
||||
* @param key Private key in PEM format, will be read from cert if NULL
|
||||
* @param len_key Length of private key PEM string
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int tls_set_certificate(struct tls *tls, const char *pem, size_t len)
|
||||
int tls_set_certificate_pem(struct tls *tls, const char *cert, size_t len_cert,
|
||||
const char *key, size_t len_key)
|
||||
{
|
||||
BIO *bio = NULL, *kbio = NULL;
|
||||
X509 *cert = NULL;
|
||||
RSA *rsa = NULL;
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
int r, err = ENOMEM;
|
||||
|
||||
if (!tls || !pem || !len)
|
||||
if (!tls || !cert || !len_cert || (key && !len_key))
|
||||
return EINVAL;
|
||||
|
||||
bio = BIO_new_mem_buf((char *)pem, (int)len);
|
||||
kbio = BIO_new_mem_buf((char *)pem, (int)len);
|
||||
if (!key) {
|
||||
key = cert;
|
||||
len_key = len_cert;
|
||||
}
|
||||
|
||||
bio = BIO_new_mem_buf((char *)cert, (int)len_cert);
|
||||
kbio = BIO_new_mem_buf((char *)key, (int)len_key);
|
||||
if (!bio || !kbio)
|
||||
goto out;
|
||||
|
||||
cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
|
||||
if (!cert || !rsa)
|
||||
x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
pkey = PEM_read_bio_PrivateKey(kbio, NULL, 0, NULL);
|
||||
if (!x509 || !pkey)
|
||||
goto out;
|
||||
|
||||
r = SSL_CTX_use_certificate(tls->ctx, cert);
|
||||
r = SSL_CTX_use_certificate(tls->ctx, x509);
|
||||
if (r != 1)
|
||||
goto out;
|
||||
|
||||
r = SSL_CTX_use_RSAPrivateKey(tls->ctx, rsa);
|
||||
r = SSL_CTX_use_PrivateKey(tls->ctx, pkey);
|
||||
if (r != 1) {
|
||||
DEBUG_WARNING("set_certificate: use_RSAPrivateKey failed\n");
|
||||
DEBUG_WARNING("set_certificate_pem: use_PrivateKey failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tls->cert)
|
||||
X509_free(tls->cert);
|
||||
|
||||
tls->cert = cert;
|
||||
cert = NULL;
|
||||
tls->cert = x509;
|
||||
x509 = NULL;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
if (rsa)
|
||||
RSA_free(rsa);
|
||||
if (x509)
|
||||
X509_free(x509);
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (bio)
|
||||
BIO_free(bio);
|
||||
if (kbio)
|
||||
|
@ -396,6 +419,92 @@ int tls_set_certificate(struct tls *tls, const char *pem, size_t len)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the certificate and private key on a TLS context
|
||||
*
|
||||
* @param tls TLS Context
|
||||
* @param keytype Private key type
|
||||
* @param cert Certificate in DER format
|
||||
* @param len_cert Length of certificate DER bytes
|
||||
* @param key Private key in DER format, will be read from cert if NULL
|
||||
* @param len_key Length of private key DER bytes
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int tls_set_certificate_der(struct tls *tls, enum tls_keytype keytype,
|
||||
const uint8_t *cert, size_t len_cert, const uint8_t *key,
|
||||
size_t len_key)
|
||||
{
|
||||
const uint8_t *buf_cert;
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
int r, type, err = ENOMEM;
|
||||
|
||||
if (!tls || !cert || !len_cert || (key && !len_key))
|
||||
return EINVAL;
|
||||
|
||||
type = keytype2int(keytype);
|
||||
if (type == EVP_PKEY_NONE)
|
||||
return EINVAL;
|
||||
|
||||
buf_cert = cert;
|
||||
|
||||
x509 = d2i_X509(NULL, &buf_cert, len_cert);
|
||||
if (!x509)
|
||||
goto out;
|
||||
|
||||
if (!key) {
|
||||
key = buf_cert;
|
||||
len_key = len_cert - (buf_cert - cert);
|
||||
}
|
||||
|
||||
pkey = d2i_PrivateKey(type, NULL, &key, len_key);
|
||||
if (!pkey)
|
||||
goto out;
|
||||
|
||||
r = SSL_CTX_use_certificate(tls->ctx, x509);
|
||||
if (r != 1)
|
||||
goto out;
|
||||
|
||||
r = SSL_CTX_use_PrivateKey(tls->ctx, pkey);
|
||||
if (r != 1) {
|
||||
DEBUG_WARNING("set_certificate_der: use_PrivateKey failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tls->cert)
|
||||
X509_free(tls->cert);
|
||||
|
||||
tls->cert = x509;
|
||||
x509 = NULL;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (x509)
|
||||
X509_free(x509);
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (err)
|
||||
ERR_clear_error();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the certificate and private key on a TLS context
|
||||
*
|
||||
* @param tls TLS Context
|
||||
* @param pem Certificate and private key in PEM format
|
||||
* @param len Length of PEM string
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int tls_set_certificate(struct tls *tls, const char *pem, size_t len)
|
||||
{
|
||||
return tls_set_certificate_pem(tls, pem, len, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static int verify_handler(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue