0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose/*
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose SSSD - certificate handling utils - NSS version
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose Copyright (C) Sumit Bose <sbose@redhat.com> 2015
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose This program is free software; you can redistribute it and/or modify
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose it under the terms of the GNU General Public License as published by
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose the Free Software Foundation; either version 3 of the License, or
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose (at your option) any later version.
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose This program is distributed in the hope that it will be useful,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose but WITHOUT ANY WARRANTY; without even the implied warranty of
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose GNU General Public License for more details.
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose You should have received a copy of the GNU General Public License
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose along with this program. If not, see <http://www.gnu.org/licenses/>.
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose*/
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose#include "config.h"
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#include <nss.h>
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#include <cert.h>
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#include <base64.h>
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#include <key.h>
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#include <prerror.h>
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose#include <ocsp.h>
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose#include <talloc.h>
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#include "util/crypto/sss_crypto.h"
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#include "util/crypto/nss/nss_util.h"
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose#include "util/cert.h"
58aa8d645fa95641431a2828e985f80c7fc36465Lukas Slebodnik#include "util/sss_endian.h"
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1)
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose#define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Boseerrno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose size_t der_size, char **pem, size_t *pem_size)
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose{
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERTCertDBHandle *handle;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERTCertificate *cert = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose SECItem der_item;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose char *ascii_crlf = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose size_t ascii_crlf_len;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose char *ascii_lf = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose char *pem_cert_str = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose int ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose size_t c;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose size_t d;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose /* initialize NSS if needed */
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = nspr_nss_init();
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (ret != EOK) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose handle = CERT_GetDefaultCertDB();
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose der_item.len = der_size;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose der_item.data = discard_const(der_blob);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (cert == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ascii_crlf = BTOA_DataToAscii(cert->derCert.data, cert->derCert.len);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (ascii_crlf == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "BTOA_DataToAscii failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = EIO;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ascii_crlf_len = strlen(ascii_crlf) + 1;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ascii_lf = talloc_size(mem_ctx, ascii_crlf_len * sizeof(char));
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (ascii_lf == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "malloc failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = ENOMEM;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose d = 0;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose for (c = 0; c < ascii_crlf_len; c++) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (ascii_crlf[c] != '\r') {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ascii_lf[d++] = ascii_crlf[c];
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose pem_cert_str = talloc_asprintf(mem_ctx, "%s\n%s\n%s\n", NS_CERT_HEADER,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ascii_lf,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose NS_CERT_TRAILER);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem_cert_str == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = ENOMEM;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem_size != NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose *pem_size = strlen(pem_cert_str);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem != NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose *pem = pem_cert_str;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose pem_cert_str = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = EOK;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bosedone:
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose talloc_free(pem_cert_str);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose talloc_free(ascii_lf);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose PORT_Free(ascii_crlf);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERT_DestroyCertificate(cert);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose}
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Boseerrno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose uint8_t **_der_blob, size_t *_der_size)
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose{
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose const char *ps;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose const char *pe;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose size_t pem_len;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose uint8_t *der_blob = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose unsigned int der_size; /* unsigned int to match 2nd parameter of
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ATOB_AsciiToData */
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERTCertDBHandle *handle;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERTCertificate *cert = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose SECItem der_item;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose int ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose char *b64 = NULL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose /* initialize NSS if needed */
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = nspr_nss_init();
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (ret != EOK) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem == NULL || *pem == '\0') {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
5231ba679402eeb0705a3ecd41f97fdd67d42a69David Kupka if ((pem = strstr(pem, NS_CERT_HEADER)) == NULL) {
5231ba679402eeb0705a3ecd41f97fdd67d42a69David Kupka DEBUG(SSSDBG_CRIT_FAILURE, "Missing PEM header.");
5231ba679402eeb0705a3ecd41f97fdd67d42a69David Kupka return EINVAL;
5231ba679402eeb0705a3ecd41f97fdd67d42a69David Kupka }
5231ba679402eeb0705a3ecd41f97fdd67d42a69David Kupka
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose pem_len = strlen(pem);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem_len <= NS_CERT_HEADER_LEN + NS_CERT_TRAILER_LEN) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, "PEM data too short.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem[NS_CERT_HEADER_LEN] != '\n') {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, "Missing newline in PEM data.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose pe = pem + pem_len - NS_CERT_TRAILER_LEN;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (pem[pem_len - 1] == '\n') {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose pe--;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (strncmp(pe, NS_CERT_TRAILER, NS_CERT_TRAILER_LEN) != 0) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM trailer.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ps = pem + NS_CERT_HEADER_LEN + 1;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose b64 = talloc_strndup(mem_ctx, ps, pe - ps);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if(b64 == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = ENOMEM;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose der_blob = ATOB_AsciiToData(b64, &der_size);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (der_blob == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "ATOB_AsciiToData failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return EIO;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose handle = CERT_GetDefaultCertDB();
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose der_item.len = der_size;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose der_item.data = der_blob;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (cert == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = EINVAL;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (_der_blob != NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose *_der_blob = talloc_memdup(mem_ctx, cert->derCert.data,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose cert->derCert.len);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (*_der_blob == NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose ret = ENOMEM;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose goto done;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (_der_size != NULL) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose *_der_size = cert->derCert.len;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose }
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bosedone:
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose PORT_Free(der_blob);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose talloc_free(b64);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose CERT_DestroyCertificate(cert);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose return ret;
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose}
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#define SSH_RSA_HEADER "ssh-rsa"
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose#define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Boseerrno_t cert_to_ssh_key(TALLOC_CTX *mem_ctx, const char *ca_db,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose const uint8_t *der_blob, size_t der_size,
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose struct cert_verify_opts *cert_verify_opts,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose uint8_t **key, size_t *key_size)
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose{
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose CERTCertDBHandle *handle;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose CERTCertificate *cert = NULL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SECItem der_item;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SECKEYPublicKey *cert_pub_key = NULL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose int ret;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose size_t size;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose uint8_t *buf = NULL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose size_t c;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose NSSInitContext *nss_ctx;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose NSSInitParameters parameters = { 0 };
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose parameters.length = sizeof (parameters);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SECStatus rv;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose SECStatus rv_verify;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose size_t exponent_prefix_len;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose size_t modulus_prefix_len;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (der_blob == NULL || der_size == 0) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose return EINVAL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose /* initialize NSS with context, we might have already called
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose * NSS_NoDB_Init() but for validation we need to have access to a DB with
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose * the trusted issuer cert. Only NSS_InitContext will really open the DB
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose * in this case. I'm not sure about how long validation might need e.g. if
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose * CRLs or OSCP is enabled, maybe it would be better to run validation in
346d6d8bf5fdb446921d754c07c8a7d913a048d5René Genz * p11_child? */
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose nss_ctx = NSS_InitContext(ca_db, "", "", SECMOD_DB, &parameters,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose NSS_INIT_READONLY);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (nss_ctx == NULL) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n",
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose PR_GetError());
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose return EIO;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose handle = CERT_GetDefaultCertDB();
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose if (cert_verify_opts->do_ocsp) {
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose rv = CERT_EnableOCSPChecking(handle);
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose if (rv != SECSuccess) {
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n",
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose PR_GetError());
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose return EIO;
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (cert_verify_opts->ocsp_default_responder != NULL
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose && cert_verify_opts->ocsp_default_responder_signing_cert != NULL) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose rv = CERT_SetOCSPDefaultResponder(handle,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose cert_verify_opts->ocsp_default_responder,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose cert_verify_opts->ocsp_default_responder_signing_cert);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (rv != SECSuccess) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose DEBUG(SSSDBG_OP_FAILURE,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose "CERT_SetOCSPDefaultResponder failed: [%d].\n",
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose PR_GetError());
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return EIO;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose rv = CERT_EnableOCSPDefaultResponder(handle);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (rv != SECSuccess) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose DEBUG(SSSDBG_OP_FAILURE,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose "CERT_EnableOCSPDefaultResponder failed: [%d].\n",
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose PR_GetError());
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return EIO;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose }
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose der_item.len = der_size;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose der_item.data = discard_const(der_blob);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (cert == NULL) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose ret = EINVAL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose goto done;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose if (cert_verify_opts->do_verification) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose rv_verify = CERT_VerifyCertificateNow(handle, cert, PR_TRUE,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose certificateUsageSSLClient,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose NULL, NULL);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose /* Disable OCSP default responder so that NSS can shutdown properly */
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (cert_verify_opts->do_ocsp
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose && cert_verify_opts->ocsp_default_responder != NULL
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose && cert_verify_opts->ocsp_default_responder_signing_cert
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose != NULL) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose rv = CERT_DisableOCSPDefaultResponder(handle);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (rv != SECSuccess) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose DEBUG(SSSDBG_OP_FAILURE,
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose "CERT_DisableOCSPDefaultResponder failed: [%d].\n",
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose PR_GetError());
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (rv_verify != SECSuccess) {
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose DEBUG(SSSDBG_CRIT_FAILURE, "CERT_VerifyCertificateNow failed [%d].\n",
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose PR_GetError());
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose ret = EACCES;
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose goto done;
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose cert_pub_key = CERT_ExtractPublicKey(cert);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (cert_pub_key == NULL) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "CERT_ExtractPublicKey failed.\n");
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose ret = EIO;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose goto done;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (cert_pub_key->keyType != rsaKey) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_CRIT_FAILURE,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose "Expected RSA public key, found unsupported [%d].\n",
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose cert_pub_key->keyType);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose ret = EINVAL;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose goto done;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
346d6d8bf5fdb446921d754c07c8a7d913a048d5René Genz /* Looks like nss drops the leading 00 which AFAIK is added to make sure
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose * the bigint is handled as positive number if the leading bit is set. */
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose exponent_prefix_len = 0;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose if (cert_pub_key->u.rsa.publicExponent.data[0] & 0x80) {
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose exponent_prefix_len = 1;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose }
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose modulus_prefix_len = 0;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose if (cert_pub_key->u.rsa.modulus.data[0] & 0x80) {
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose modulus_prefix_len = 1;
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose size = SSH_RSA_HEADER_LEN + 3 * sizeof(uint32_t)
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose + cert_pub_key->u.rsa.modulus.len
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose + cert_pub_key->u.rsa.publicExponent.len
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose + exponent_prefix_len + modulus_prefix_len;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose buf = talloc_size(mem_ctx, size);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (buf == NULL) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose ret = ENOMEM;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose goto done;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose c = 0;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SAFEALIGN_SET_UINT32(buf, htobe32(SSH_RSA_HEADER_LEN), &c);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose safealign_memcpy(&buf[c], SSH_RSA_HEADER, SSH_RSA_HEADER_LEN, &c);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SAFEALIGN_SET_UINT32(&buf[c],
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose htobe32(cert_pub_key->u.rsa.publicExponent.len
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose + exponent_prefix_len), &c);
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose if (exponent_prefix_len == 1) {
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose SAFEALIGN_SETMEM_VALUE(&buf[c], '\0', unsigned char, &c);
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose safealign_memcpy(&buf[c], cert_pub_key->u.rsa.publicExponent.data,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose cert_pub_key->u.rsa.publicExponent.len, &c);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SAFEALIGN_SET_UINT32(&buf[c],
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose htobe32(cert_pub_key->u.rsa.modulus.len
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose + modulus_prefix_len ), &c);
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose if (modulus_prefix_len == 1) {
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose SAFEALIGN_SETMEM_VALUE(&buf[c], '\0', unsigned char, &c);
8b2bd0587af6ed6bbd7eab7a332ec88de6b7c36cSumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose safealign_memcpy(&buf[c], cert_pub_key->u.rsa.modulus.data,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose cert_pub_key->u.rsa.modulus.len, &c);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose *key = buf;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose *key_size = size;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose ret = EOK;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bosedone:
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (ret != EOK) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose talloc_free(buf);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose SECKEY_DestroyPublicKey(cert_pub_key);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose CERT_DestroyCertificate(cert);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose rv = NSS_ShutdownContext(nss_ctx);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose if (rv != SECSuccess) {
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n",
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose PR_GetError());
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose }
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose return ret;
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose}