diff options
author | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2008-01-31 11:46:32 +0000 |
---|---|---|
committer | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2008-01-31 11:46:32 +0000 |
commit | 803664519e6edbb2b298861a7133e204761ae0e3 (patch) | |
tree | 550ca448a37d65003ac36f40ad1e33946164e210 /src/ne_gnutls.c | |
parent | 91d0fcf1f794acc90a671bf5557d2d2a505843f7 (diff) | |
download | neon-803664519e6edbb2b298861a7133e204761ae0e3.tar.gz |
Add support for PKCS#12 client certs which don't include a private
key:
* src/ne_gnutls.c (struct ne_ssl_client_cert_s): Add keyless flag.
(dup_client_cert): Support keyless clicerts.
(pkcs12_parse): Make pkey handling optional.
(read_client_cert): Factor out from ne_ssl_clicert_read; take additional
key_required flag; fail if cert or key is required and not supplied;
initialize keyless flag.
(ne_ssl_clicert_read): Reimplement using read_client_cert.
(ne_ssl_clicert_exkey_read): New function.
(ne_ssl_clicert_decrypt): Handle keyless failure case.
* src/ne_openssl.c (ne_ssl_clicert_exkey_read): Add stub.
* src/ne_stubssl.c (ne_ssl_clicert_exkey_read): Add stub.
* test/ssl.c (load_client_cert): Test ne_ssl_clicert_exkey_read.
* test/makekeys.sh: Generate keyless ccert.
git-svn-id: http://svn.webdav.org/repos/projects/neon/trunk@1316 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
Diffstat (limited to 'src/ne_gnutls.c')
-rw-r--r-- | src/ne_gnutls.c | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/src/ne_gnutls.c b/src/ne_gnutls.c index c807ff7..924f635 100644 --- a/src/ne_gnutls.c +++ b/src/ne_gnutls.c @@ -1,6 +1,6 @@ /* neon SSL/TLS support using GNU TLS - Copyright (C) 2002-2007, Joe Orton <joe@manyfish.co.uk> + Copyright (C) 2002-2008, Joe Orton <joe@manyfish.co.uk> Copyright (C) 2004, Aleix Conchillo Flaque <aleix@member.fsf.org> This library is free software; you can redistribute it and/or @@ -69,6 +69,7 @@ struct ne_ssl_certificate_s { struct ne_ssl_client_cert_s { gnutls_pkcs12 p12; int decrypted; /* non-zero if successfully decrypted. */ + int keyless; ne_ssl_certificate cert; gnutls_x509_privkey pkey; char *friendly_name; @@ -502,13 +503,18 @@ static ne_ssl_client_cert *dup_client_cert(const ne_ssl_client_cert *cc) ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc); newcc->decrypted = 1; - - ret = gnutls_x509_privkey_init(&newcc->pkey); - if (ret != 0) goto dup_error; - - ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey); - if (ret != 0) goto dup_error; + if (cc->keyless) { + newcc->keyless = 1; + } + else { + ret = gnutls_x509_privkey_init(&newcc->pkey); + if (ret != 0) goto dup_error; + + ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey); + if (ret != 0) goto dup_error; + } + newcc->cert.subject = x509_crt_copy(cc->cert.subject); if (!newcc->cert.subject) goto dup_error; @@ -814,7 +820,8 @@ static int read_to_datum(const char *filename, gnutls_datum *datum) /* Parses a PKCS#12 structure and loads the certificate, private key * and friendly name if possible. Returns zero on success, non-zero - * on error. */ + * on error. pkey may be NULL, in which case any contained private key + * is ignored. */ static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey, gnutls_x509_crt *x5, char **friendly_name, const char *password) @@ -850,6 +857,8 @@ static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey, switch (type) { case GNUTLS_BAG_PKCS8_KEY: case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: + if (!pkey) continue; + gnutls_x509_privkey_init(pkey); ret = gnutls_pkcs12_bag_get_data(bag, j, &data); @@ -891,7 +900,7 @@ static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey, return ret; } -ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) +static ne_ssl_client_cert *read_client_cert(const char *filename, int key_required) { int ret; gnutls_datum data; @@ -916,7 +925,15 @@ ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) } if (gnutls_pkcs12_verify_mac(p12, "") == 0) { - if (pkcs12_parse(p12, &pkey, &cert, &friendly_name, "") != 0) { + if (pkcs12_parse(p12, key_required ? &pkey : NULL, &cert, + &friendly_name, "") != 0) { + gnutls_pkcs12_deinit(p12); + return NULL; + } + + if (!cert || (!pkey && key_required)) { + if (cert) gnutls_x509_crt_deinit(cert); + if (pkey) gnutls_x509_privkey_deinit(pkey); gnutls_pkcs12_deinit(p12); return NULL; } @@ -924,6 +941,7 @@ ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) cc = ne_calloc(sizeof *cc); cc->pkey = pkey; cc->decrypted = 1; + cc->keyless = !key_required; cc->friendly_name = friendly_name; populate_cert(&cc->cert, cert); gnutls_pkcs12_deinit(p12); @@ -934,10 +952,21 @@ ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) * seems to break horribly. */ cc = ne_calloc(sizeof *cc); cc->p12 = p12; + cc->keyless = !key_required; return cc; } } +ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename) +{ + return read_client_cert(filename, 1); +} + +ne_ssl_client_cert *ne_ssl_clicert_exkey_read(const char *filename) +{ + return read_client_cert(filename, 0); +} + int ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc) { return !cc->decrypted; @@ -956,6 +985,12 @@ int ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password) ret = pkcs12_parse(cc->p12, &pkey, &cert, NULL, password); if (ret < 0) return ret; + + if (!cert || (!pkey && !cc->keyless)) { + if (cert) gnutls_x509_crt_deinit(cert); + if (pkey) gnutls_x509_privkey_deinit(pkey); + return -1; + } gnutls_pkcs12_deinit(cc->p12); populate_cert(&cc->cert, cert); |