From 03469187014a219d7d7469be969a2a9070500f5c Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Tue, 26 Apr 2016 20:21:23 +0100 Subject: [PATCH] add mkfingerprint program --- .gitignore | 1 + librb/include/rb_commio.h | 1 + librb/src/export-syms.txt | 1 + librb/src/gnutls.c | 81 ++++++++++++++++++--------- librb/src/mbedtls.c | 60 +++++++++++++------- librb/src/nossl.c | 6 ++ librb/src/openssl.c | 113 +++++++++++++++++++++++--------------- tools/Makefile.am | 5 +- tools/mkfingerprint.c | 81 +++++++++++++++++++++++++++ 9 files changed, 258 insertions(+), 91 deletions(-) create mode 100644 tools/mkfingerprint.c diff --git a/.gitignore b/.gitignore index 9fd416b3..97a17b38 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ ssld/ssld wsockd/wsockd testsuite/ircd.pid.* tools/charybdis-mkpasswd +tools/charybdis-mkfingerprint tools/genssl tools/mkpasswd tools/viconf diff --git a/librb/include/rb_commio.h b/librb/include/rb_commio.h index 4be81773..f4dc687b 100644 --- a/librb/include/rb_commio.h +++ b/librb/include/rb_commio.h @@ -156,6 +156,7 @@ int rb_fd_ssl(rb_fde_t *F); rb_platform_fd_t rb_get_fd(rb_fde_t *F); const char *rb_get_ssl_strerror(rb_fde_t *F); int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method); +int rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method); rb_fde_t *rb_get_fde(rb_platform_fd_t fd); diff --git a/librb/src/export-syms.txt b/librb/src/export-syms.txt index bd804eb1..a7059d53 100644 --- a/librb/src/export-syms.txt +++ b/librb/src/export-syms.txt @@ -59,6 +59,7 @@ rb_get_iotype rb_get_random rb_get_sockerr rb_get_ssl_certfp +rb_get_ssl_certfp_file rb_get_ssl_strerror rb_get_type rb_getmaxconnect diff --git a/librb/src/gnutls.c b/librb/src/gnutls.c index 6ceffd0d..cea17d80 100644 --- a/librb/src/gnutls.c +++ b/librb/src/gnutls.c @@ -602,37 +602,14 @@ rb_get_ssl_strerror(rb_fde_t *F) return gnutls_strerror(F->ssl_errno); } -int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +static unsigned int +make_certfp(gnutls_x509_crt_t cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { - gnutls_x509_crt_t cert; gnutls_digest_algorithm_t algo; - unsigned int cert_list_size; - const gnutls_datum_t *cert_list; uint8_t digest[RB_SSL_CERTFP_LEN * 2]; size_t digest_size; - int len; bool spki = false; - - if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) - return 0; - - if (gnutls_x509_crt_init(&cert) < 0) - return 0; - - cert_list_size = 0; - cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); - if (cert_list == NULL) - { - gnutls_x509_crt_deinit(cert); - return 0; - } - - if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) - { - gnutls_x509_crt_deinit(cert); - return 0; - } + unsigned int len; switch(method) { @@ -701,7 +678,59 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) if (len) memcpy(certfp, digest, len); + return len; +} +int +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + gnutls_x509_crt_t cert; + unsigned int cert_list_size; + const gnutls_datum_t *cert_list; + int len; + + if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) + return 0; + + if (gnutls_x509_crt_init(&cert) < 0) + return 0; + + cert_list_size = 0; + cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); + if (cert_list == NULL) + { + gnutls_x509_crt_deinit(cert); + return 0; + } + + if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) + { + gnutls_x509_crt_deinit(cert); + return 0; + } + + len = make_certfp(cert, certfp, method); + gnutls_x509_crt_deinit(cert); + return len; +} + +int +rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + gnutls_x509_crt_t cert; + gnutls_datum_t *d_cert; + unsigned int len; + + if ((d_cert = rb_load_file_into_datum_t(filename)) == NULL) + return -1; + + if (gnutls_x509_crt_init(&cert) < 0) + return -1; + + if (gnutls_x509_crt_import(cert, d_cert, GNUTLS_X509_FMT_PEM) != 0) + return -1; + + len = make_certfp(cert, certfp, method); gnutls_x509_crt_deinit(cert); return len; } diff --git a/librb/src/mbedtls.c b/librb/src/mbedtls.c index 55cdccdc..c2d4ba02 100644 --- a/librb/src/mbedtls.c +++ b/librb/src/mbedtls.c @@ -537,53 +537,47 @@ rb_get_ssl_strerror(rb_fde_t *F) #endif } -int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +static size_t +make_certfp(const mbedtls_x509_crt *peer_cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { - const mbedtls_x509_crt *peer_cert; - uint8_t hash[RB_SSL_CERTFP_LEN]; - size_t hashlen; const mbedtls_md_info_t *md_info; mbedtls_md_type_t md_type; - int ret; bool spki = false; + int ret; + size_t len; switch (method) { case RB_SSL_CERTFP_METH_CERT_SHA1: md_type = MBEDTLS_MD_SHA1; - hashlen = RB_SSL_CERTFP_LEN_SHA1; + len = RB_SSL_CERTFP_LEN_SHA1; break; case RB_SSL_CERTFP_METH_SPKI_SHA256: spki = true; case RB_SSL_CERTFP_METH_CERT_SHA256: md_type = MBEDTLS_MD_SHA256; - hashlen = RB_SSL_CERTFP_LEN_SHA256; + len = RB_SSL_CERTFP_LEN_SHA256; break; case RB_SSL_CERTFP_METH_SPKI_SHA512: spki = true; case RB_SSL_CERTFP_METH_CERT_SHA512: md_type = MBEDTLS_MD_SHA512; - hashlen = RB_SSL_CERTFP_LEN_SHA512; + len = RB_SSL_CERTFP_LEN_SHA512; break; default: return 0; } - peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); - if (peer_cert == NULL) - return 0; - md_info = mbedtls_md_info_from_type(md_type); if (md_info == NULL) return 0; if (!spki) { - if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, hash)) != 0) + if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, certfp)) != 0) { rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret); - hashlen = 0; + len = 0; } } else @@ -596,21 +590,45 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) if (der_pubkey_len < 0) { rb_lib_log("rb_get_ssl_certfp: unable to get pubkey for F: %p, -0x%x", -der_pubkey_len); - hashlen = 0; + len = 0; } - else if ((ret = mbedtls_md(md_info, der_pubkey+(der_pubkey_bufsz-der_pubkey_len), der_pubkey_len, hash)) != 0) + else if ((ret = mbedtls_md(md_info, der_pubkey+(der_pubkey_bufsz-der_pubkey_len), der_pubkey_len, certfp)) != 0) { rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret); - hashlen = 0; + len = 0; } rb_free(der_pubkey); } - if (hashlen) - memcpy(certfp, hash, hashlen); + return len; +} - return hashlen; +int +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + const mbedtls_x509_crt *peer_cert; + + peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); + if (peer_cert == NULL) + return 0; + + return make_certfp(peer_cert, certfp, method); +} + +int +rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + mbedtls_x509_crt cert; + int ret; + + mbedtls_x509_crt_init(&cert); + + ret = mbedtls_x509_crt_parse_file(&cert, filename); + if (ret != 0) + return -1; + + return make_certfp(&cert, certfp, method); } int diff --git a/librb/src/nossl.c b/librb/src/nossl.c index 85e6e51c..8d1ff67f 100644 --- a/librb/src/nossl.c +++ b/librb/src/nossl.c @@ -98,6 +98,12 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) return 0; } +int +rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + return 0; +} + void rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) { diff --git a/librb/src/openssl.c b/librb/src/openssl.c index 444290fd..b7c6981b 100644 --- a/librb/src/openssl.c +++ b/librb/src/openssl.c @@ -685,6 +685,55 @@ rb_get_ssl_strerror(rb_fde_t *F) return get_ssl_error(F->ssl_errno); } +static unsigned int +make_certfp(X509 *cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + const ASN1_ITEM *it; + const EVP_MD *evp; + void *data; + unsigned int len; + + switch(method) + { + case RB_SSL_CERTFP_METH_CERT_SHA1: + it = ASN1_ITEM_rptr(X509); + evp = EVP_sha1(); + data = cert; + len = RB_SSL_CERTFP_LEN_SHA1; + break; + case RB_SSL_CERTFP_METH_CERT_SHA256: + it = ASN1_ITEM_rptr(X509); + evp = EVP_sha256(); + data = cert; + len = RB_SSL_CERTFP_LEN_SHA256; + break; + case RB_SSL_CERTFP_METH_CERT_SHA512: + it = ASN1_ITEM_rptr(X509); + evp = EVP_sha512(); + data = cert; + len = RB_SSL_CERTFP_LEN_SHA512; + break; + case RB_SSL_CERTFP_METH_SPKI_SHA256: + it = ASN1_ITEM_rptr(X509_PUBKEY); + evp = EVP_sha256(); + data = X509_get_X509_PUBKEY(cert); + len = RB_SSL_CERTFP_LEN_SHA256; + break; + case RB_SSL_CERTFP_METH_SPKI_SHA512: + it = ASN1_ITEM_rptr(X509_PUBKEY); + evp = EVP_sha512(); + data = X509_get_X509_PUBKEY(cert); + len = RB_SSL_CERTFP_LEN_SHA512; + break; + default: + return 0; + } + + if (ASN1_item_digest(it, evp, data, certfp, &len) != 1) + len = 0; + return len; +} + int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { @@ -708,49 +757,7 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) res == X509_V_ERR_CERT_NOT_YET_VALID || res == X509_V_ERR_CERT_HAS_EXPIRED) { - const ASN1_ITEM *it; - const EVP_MD *evp; - void *data; - unsigned int len; - - switch(method) - { - case RB_SSL_CERTFP_METH_CERT_SHA1: - it = ASN1_ITEM_rptr(X509); - evp = EVP_sha1(); - data = cert; - len = RB_SSL_CERTFP_LEN_SHA1; - break; - case RB_SSL_CERTFP_METH_CERT_SHA256: - it = ASN1_ITEM_rptr(X509); - evp = EVP_sha256(); - data = cert; - len = RB_SSL_CERTFP_LEN_SHA256; - break; - case RB_SSL_CERTFP_METH_CERT_SHA512: - it = ASN1_ITEM_rptr(X509); - evp = EVP_sha512(); - data = cert; - len = RB_SSL_CERTFP_LEN_SHA512; - break; - case RB_SSL_CERTFP_METH_SPKI_SHA256: - it = ASN1_ITEM_rptr(X509_PUBKEY); - evp = EVP_sha256(); - data = X509_get_X509_PUBKEY(cert); - len = RB_SSL_CERTFP_LEN_SHA256; - break; - case RB_SSL_CERTFP_METH_SPKI_SHA512: - it = ASN1_ITEM_rptr(X509_PUBKEY); - evp = EVP_sha512(); - data = X509_get_X509_PUBKEY(cert); - len = RB_SSL_CERTFP_LEN_SHA512; - break; - default: - return 0; - } - - if (ASN1_item_digest(it, evp, data, certfp, &len) != 1) - len = 0; + unsigned int len = make_certfp(cert, certfp, method); X509_free(cert); return len; } @@ -760,6 +767,26 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) return 0; } +int +rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +{ + X509 *cert; + FILE *f = fopen(filename, "r"); + + if (!f) + return -1; + + cert = PEM_read_X509(f, NULL, NULL, NULL); + fclose(f); + + if (cert) { + unsigned int len = make_certfp(cert, certfp, method); + X509_free(cert); + return len; + } + return 0; +} + int rb_supports_ssl(void) { diff --git a/tools/Makefile.am b/tools/Makefile.am index 44108212..607bca31 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,6 +1,9 @@ -bin_PROGRAMS = charybdis-mkpasswd +bin_PROGRAMS = charybdis-mkpasswd charybdis-mkfingerprint AM_CFLAGS=$(WARNFLAGS) AM_CPPFLAGS = $(DEFAULT_INCLUDES) -I../librb/include -I. charybdis_mkpasswd_SOURCES = mkpasswd.c charybdis_mkpasswd_LDADD = ../librb/src/librb.la + +charybdis_mkfingerprint_SOURCES = mkfingerprint.c +charybdis_mkfingerprint_LDADD = ../librb/src/librb.la diff --git a/tools/mkfingerprint.c b/tools/mkfingerprint.c new file mode 100644 index 00000000..edb4087a --- /dev/null +++ b/tools/mkfingerprint.c @@ -0,0 +1,81 @@ +/* + * mkfingerprint.c: Create certificate fingerprints using librb + * Copyright 2016 simon Arlott + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +#include +#include +#include +#include +#include "rb_lib.h" +#include "certfp.h" + +int main(int argc, char *argv[]) +{ + uint8_t certfp[RB_SSL_CERTFP_LEN+1] = { 0 }; + const char *method_str; + const char *filename; + int method; + const char *prefix; + int ret; + int i; + + if (argc != 3) { + printf("mkfingerprint \n"); + printf(" Valid methods: sha1, sha256, sha512, spki_sha256, spki_sha512\n"); + return 1; + } + + method_str = argv[1]; + filename = argv[2]; + + if (!strcmp(method_str, "sha1")) { + method = RB_SSL_CERTFP_METH_CERT_SHA1; + prefix = CERTFP_PREFIX_CERT_SHA1; + } else if (!strcmp(method_str, "sha256")) { + method = RB_SSL_CERTFP_METH_CERT_SHA256; + prefix = CERTFP_PREFIX_CERT_SHA256; + } else if (!strcmp(method_str, "sha512")) { + method = RB_SSL_CERTFP_METH_CERT_SHA512; + prefix = CERTFP_PREFIX_CERT_SHA512; + } else if (!strcmp(method_str, "spki_sha256")) { + method = RB_SSL_CERTFP_METH_SPKI_SHA256; + prefix = CERTFP_PREFIX_SPKI_SHA256; + } else if (!strcmp(method_str, "spki_sha512")) { + method = RB_SSL_CERTFP_METH_SPKI_SHA512; + prefix = CERTFP_PREFIX_SPKI_SHA512; + } else { + printf("Unknown method: %s\n", method_str); + return 1; + } + + ret = rb_get_ssl_certfp_file(filename, certfp, method); + if (ret < 0) { + perror(filename); + return 1; + } else if (ret == 0) { + fprintf(stderr, "Unknown error\n"); + return 1; + } + + printf("%s", prefix); + for (i = 0; i < strlen(certfp); i++) { + printf("%02x", certfp[i]); + } + printf("\n"); + return 0; +}