From cbbdb6250744154bf9b5d0718ec68f2b63dfaff0 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 22 Jun 2015 16:36:36 +0200 Subject: [PATCH 30/37] utils: add NSS version of cert utils Reviewed-by: Jakub Hrozek --- Makefile.am | 29 ++++- configure.ac | 4 +- contrib/sssd.spec.in | 1 - src/tests/cmocka/test_cert_utils.c | 4 + src/util/cert/nss/cert.c | 212 +++++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 src/util/cert/nss/cert.c diff --git a/Makefile.am b/Makefile.am index 912bfc6641465ef5cd2ff2cce9975b4027c3218d..277166ec66b3d67101e628990e68704c886b0c59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -709,6 +709,17 @@ if HAVE_NSS src/util/crypto/nss/nss_util.c SSS_CRYPT_CFLAGS = $(NSS_CFLAGS) SSS_CRYPT_LIBS = $(NSS_LIBS) + + SSS_CERT_SOURCES = \ + src/util/cert/cert_common.c \ + src/util/cert/nss/cert.c \ + $(NULL) + SSS_CERT_CFLAGS = \ + $(NSS_CFLAGS) \ + $(NULL) + SSS_CERT_LIBS = \ + $(NSS_LIBS) \ + $(NULL) else SSS_CRYPT_SOURCES = src/util/crypto/libcrypto/crypto_base64.c \ src/util/crypto/libcrypto/crypto_hmac_sha1.c \ @@ -716,6 +727,17 @@ else src/util/crypto/libcrypto/crypto_obfuscate.c SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS) SSS_CRYPT_LIBS = $(CRYPTO_LIBS) + + SSS_CERT_SOURCES = \ + src/util/cert/cert_common.c \ + src/util/cert/libcrypto/cert.c \ + $(NULL) + SSS_CERT_CFLAGS = \ + $(CRYPTO_CFLAGS) \ + $(NULL) + SSS_CERT_LIBS = \ + $(CRYPTO_LIBS) \ + $(NULL) endif libsss_crypt_la_SOURCES = \ @@ -735,14 +757,13 @@ libsss_crypt_la_LDFLAGS = \ pkglib_LTLIBRARIES += libsss_cert.la libsss_cert_la_SOURCES = \ - src/util/cert/cert_common.c \ - src/util/cert/libcrypto/cert.c \ + $(SSS_CERT_SOURCES) \ $(NULL) libsss_cert_la_CFLAGS = \ - $(CRYPTO_CFLAGS) \ + $(SSS_CERT_CFLAGS) \ $(NULL) libsss_cert_la_LIBADD = \ - $(CRYPTO_LIBS) \ + $(SSS_CERT_LIBS) \ $(TALLOC_LIBS) \ libsss_crypt.la \ libsss_debug.la \ diff --git a/configure.ac b/configure.ac index 29bedf74db6594b5788d51570514a07e082d5e42..4b4f8f3228bf13c594c86e1e39474a1d02ffd984 100644 --- a/configure.ac +++ b/configure.ac @@ -341,7 +341,9 @@ if test x$cryptolib = xnss; then AM_CHECK_NSS fi -AM_CHECK_LIBCRYPTO +if test x$cryptolib = xlibcrypto; then + AM_CHECK_LIBCRYPTO +fi AM_CHECK_INOTIFY diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index f050501ff9d0711a0da7f094ee968cae87a3f49b..54260e32e24ece372ed7130ab29d766bb1923f77 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -106,7 +106,6 @@ BuildRequires: dbus-libs BuildRequires: openldap-devel BuildRequires: pam-devel BuildRequires: nss-devel -BuildRequires: openssl-devel BuildRequires: nspr-devel BuildRequires: pcre-devel BuildRequires: libxslt diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c index 5bcbafb27dbdff596c07b8aad10ca15a35ff4ef5..8063b1a65e8692142cbb3cf82fe41afa6567bc91 100644 --- a/src/tests/cmocka/test_cert_utils.c +++ b/src/tests/cmocka/test_cert_utils.c @@ -23,7 +23,9 @@ */ #include +#ifdef HAVE_LIBCRYPTO #include +#endif #include "util/cert.h" #include "tests/cmocka/common_mock.h" @@ -349,7 +351,9 @@ int main(int argc, const char *argv[]) ret = cmocka_run_group_tests(tests, NULL, NULL); +#ifdef HAVE_LIBCRYPTO CRYPTO_cleanup_all_ex_data(); /* to make valgrind happy */ +#endif #ifdef HAVE_NSS /* Cleanup NSS and NSPR to make valgrind happy. */ diff --git a/src/util/cert/nss/cert.c b/src/util/cert/nss/cert.c new file mode 100644 index 0000000000000000000000000000000000000000..a20abf63a10de9a5e9810f1c7d56686d063d60c7 --- /dev/null +++ b/src/util/cert/nss/cert.c @@ -0,0 +1,212 @@ + +/* + SSSD - certificate handling utils - NSS version + + Copyright (C) Sumit Bose 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "util/util.h" + +#include +#include + +#include "util/crypto/nss/nss_util.h" + +#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define NS_CERT_TRAILER "-----END CERTIFICATE-----" +#define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1) +#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1) + +errno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob, + size_t der_size, char **pem, size_t *pem_size) +{ + + CERTCertDBHandle *handle; + CERTCertificate *cert = NULL; + SECItem der_item; + char *ascii_crlf = NULL; + size_t ascii_crlf_len; + char *ascii_lf = NULL; + char *pem_cert_str = NULL; + int ret; + size_t c; + size_t d; + + /* initialize NSS if needed */ + ret = nspr_nss_init(); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n"); + return ret; + } + + handle = CERT_GetDefaultCertDB(); + + der_item.len = der_size; + der_item.data = discard_const(der_blob); + + cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE); + if (cert == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n"); + return EINVAL; + } + + ascii_crlf = BTOA_DataToAscii(cert->derCert.data, cert->derCert.len); + if (ascii_crlf == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "BTOA_DataToAscii failed.\n"); + ret = EIO; + goto done; + } + + ascii_crlf_len = strlen(ascii_crlf) + 1; + ascii_lf = talloc_size(mem_ctx, ascii_crlf_len * sizeof(char)); + if (ascii_lf == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "malloc failed.\n"); + ret = ENOMEM; + goto done; + } + + d = 0; + for (c = 0; c < ascii_crlf_len; c++) { + if (ascii_crlf[c] != '\r') { + ascii_lf[d++] = ascii_crlf[c]; + } + } + + pem_cert_str = talloc_asprintf(mem_ctx, "%s\n%s\n%s\n", NS_CERT_HEADER, + ascii_lf, + NS_CERT_TRAILER); + if (pem_cert_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); + ret = ENOMEM; + goto done; + } + + if (pem_size != NULL) { + *pem_size = strlen(pem_cert_str); + } + + if (pem != NULL) { + *pem = pem_cert_str; + pem_cert_str = NULL; + } + + ret = EOK; +done: + talloc_free(pem_cert_str); + talloc_free(ascii_lf); + PORT_Free(ascii_crlf); + CERT_DestroyCertificate(cert); + + return ret; +} + +errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem, + uint8_t **_der_blob, size_t *_der_size) +{ + const char *ps; + const char *pe; + size_t pem_len; + uint8_t *der_blob = NULL; + unsigned int der_size; /* unsigned int to match 2nd parameter of + ATOB_AsciiToData */ + CERTCertDBHandle *handle; + CERTCertificate *cert = NULL; + SECItem der_item; + int ret; + char *b64 = NULL; + + /* initialize NSS if needed */ + ret = nspr_nss_init(); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n"); + return ret; + } + + if (pem == NULL || *pem == '\0') { + return EINVAL; + } + + pem_len = strlen(pem); + if (pem_len <= NS_CERT_HEADER_LEN + NS_CERT_TRAILER_LEN) { + DEBUG(SSSDBG_CRIT_FAILURE, "PEM data too short.\n"); + return EINVAL; + } + + if (strncmp(pem, NS_CERT_HEADER, NS_CERT_HEADER_LEN) != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM header.\n"); + return EINVAL; + } + if (pem[NS_CERT_HEADER_LEN] != '\n') { + DEBUG(SSSDBG_CRIT_FAILURE, "Missing newline in PEM data.\n"); + return EINVAL; + } + + pe = pem + pem_len - NS_CERT_TRAILER_LEN; + if (pem[pem_len - 1] == '\n') { + pe--; + } + if (strncmp(pe, NS_CERT_TRAILER, NS_CERT_TRAILER_LEN) != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM trailer.\n"); + return EINVAL; + } + + ps = pem + NS_CERT_HEADER_LEN + 1; + + b64 = talloc_strndup(mem_ctx, ps, pe - ps); + if(b64 == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + ret = ENOMEM; + goto done; + } + + der_blob = ATOB_AsciiToData(b64, &der_size); + if (der_blob == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ATOB_AsciiToData failed.\n"); + return EIO; + } + + handle = CERT_GetDefaultCertDB(); + + der_item.len = der_size; + der_item.data = der_blob; + + cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE); + if (cert == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n"); + ret = EINVAL; + goto done; + } + + if (_der_blob != NULL) { + *_der_blob = talloc_memdup(mem_ctx, cert->derCert.data, + cert->derCert.len); + if (*_der_blob == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n"); + ret = ENOMEM; + goto done; + } + } + + if (_der_size != NULL) { + *_der_size = cert->derCert.len; + } +done: + PORT_Free(der_blob); + talloc_free(b64); + CERT_DestroyCertificate(cert); + + return ret; +} -- 2.4.3