Accept PKCS#12 file in either key or cert
This commit is contained in:
25
src/conn.c
25
src/conn.c
@@ -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.
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user