Accept PKCS#12 file in either key or cert

This commit is contained in:
Stu Tomlinson
2022-06-22 10:41:26 +01:00
parent e90a6e9f71
commit 3d01915407
5 changed files with 33 additions and 17 deletions

View File

@@ -573,11 +573,12 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it must be passed via
* the `key` parameter and `cert` must be NULL.
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup TLS
@@ -589,13 +590,21 @@ void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
strophe_free(conn->ctx, conn->tls_client_cert);
if (cert)
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
else
conn->tls_client_cert = NULL;
conn->tls_client_cert = NULL;
if (conn->tls_client_key)
strophe_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
conn->tls_client_key = NULL;
if (cert && key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
} else if (cert && !key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
} else if (!cert && key) {
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
conn->tls_client_cert = strophe_strdup(conn->ctx, key);
}
}
/** Get the number of xmppAddr entries in the client certificate.

View File

@@ -221,7 +221,7 @@ int tls_caching_password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn)
int ret;
unsigned char hash[XMPP_SHA1_DIGEST_SIZE];
const char *fname = conn->tls_client_key;
const char *fname = conn->tls_client_cert;
size_t fname_len = strlen(fname);
xmpp_sha1_digest((void *)fname, fname_len, hash);
if (fname_len && fname_len == conn->password_cache.fnamelen &&

View File

@@ -95,7 +95,7 @@ static gnutls_x509_crt_t _tls_load_cert_p12(xmpp_conn_t *conn)
int err = -1;
if (gnutls_pkcs12_init(&p12) < 0)
return NULL;
if (gnutls_load_file(conn->tls_client_key, &data) < 0)
if (gnutls_load_file(conn->tls_client_cert, &data) < 0)
goto error_out;
if (gnutls_pkcs12_import(p12, &data, GNUTLS_X509_FMT_DER, 0) < 0)
goto error_out2;
@@ -168,7 +168,7 @@ static gnutls_x509_crt_t _tls_load_cert(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
if (!conn->tls_client_cert && conn->tls_client_key) {
if (conn->tls_client_cert && !conn->tls_client_key) {
return _tls_load_cert_p12(conn);
}
return _tls_load_cert_x509(conn);
@@ -459,7 +459,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
}
strophe_debug(tls->ctx, "tls", "wrong password?");
}
} else if (conn->tls_client_key) {
} else if (conn->tls_client_cert) {
unsigned int retries = 0;
while (retries++ < conn->password_retries) {
@@ -470,7 +470,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
if (passlen < 0)
continue;
int err = gnutls_certificate_set_x509_simple_pkcs12_file(
tls->cred, conn->tls_client_key, GNUTLS_X509_FMT_DER, pass);
tls->cred, conn->tls_client_cert, GNUTLS_X509_FMT_DER,
pass);
memset(pass, 0, sizeof(pass));
if (err == 0)
break;

View File

@@ -616,7 +616,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
ERR_GET_LIB(err), ERR_GET_REASON(err));
goto err_free_ctx;
}
} else if (conn->tls_client_key) {
} else if (conn->tls_client_cert) {
EVP_PKEY *pkey = NULL;
STACK_OF(X509) *ca = NULL;
X509 *cert = _tls_cert_read_p12(conn, &pkey, &ca);
@@ -974,7 +974,7 @@ _tls_cert_read_p12(xmpp_conn_t *conn, EVP_PKEY **pkey, STACK_OF(X509) * *ca)
return conn->tls->client_cert;
X509 *cert = NULL;
PKCS12 *p12 = NULL;
BIO *f = BIO_new_file(conn->tls_client_key, "rb");
BIO *f = BIO_new_file(conn->tls_client_cert, "rb");
if (!f) {
strophe_debug(conn->ctx, "tls", "f == NULL");
goto error_out;
@@ -1034,7 +1034,7 @@ static X509 *_tls_cert_read(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
if (!conn->tls_client_cert && conn->tls_client_key) {
if (conn->tls_client_cert && !conn->tls_client_key) {
return _tls_cert_read_p12(conn, NULL, NULL);
}
return _tls_cert_read_x509(conn);

View File

@@ -43,6 +43,9 @@ int main()
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL},
};
const char *srcdir;
@@ -68,7 +71,10 @@ int main()
else
certfile = NULL;
snprintf(keyfile, MAXPATHLEN, "%s/%s", srcdir, client_cert[m].key);
if (client_cert[m].key)
snprintf(keyfile, MAXPATHLEN, "%s/%s", srcdir, client_cert[m].key);
else
keyfile = NULL;
if (client_cert[m].needs_callback)
xmpp_conn_set_password_callback(conn, password_callback, NULL);