diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2008-12-21 03:02:54 +0100 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2008-12-21 03:02:54 +0100 |
commit | dd0c061770b90039e605e68a44327d968981c386 (patch) | |
tree | fc34c8dd0e5892c672c0bf6b3a96d41e47e599d7 | |
parent | 33c16185e500e18dbf364dc183a2ce713448931f (diff) | |
download | eurephia-dd0c061770b90039e605e68a44327d968981c386.tar.gz eurephia-dd0c061770b90039e605e68a44327d968981c386.tar.xz eurephia-dd0c061770b90039e605e68a44327d968981c386.zip |
Moved the certfile parsing out from certificate.c into parse_certificate_files.c
Changed certinfo.[ch] to add cert.digest as well, and using this
modified struct to handle the parse result after parsing the certfile.
-rw-r--r-- | common/certinfo.c | 2 | ||||
-rw-r--r-- | common/certinfo.h | 1 | ||||
-rw-r--r-- | eurephiadm/CMakeLists.txt | 2 | ||||
-rw-r--r-- | eurephiadm/commands/certificates.c | 164 | ||||
-rw-r--r-- | eurephiadm/parse_certificate_files.c | 192 | ||||
-rw-r--r-- | eurephiadm/parse_certificate_files.h | 38 |
6 files changed, 250 insertions, 149 deletions
diff --git a/common/certinfo.c b/common/certinfo.c index bb68a53..d3fccb2 100644 --- a/common/certinfo.c +++ b/common/certinfo.c @@ -80,6 +80,8 @@ void free_certinfo(certinfo *p) { if( p == NULL ) return; + if( p->digest != NULL ) + free(p->digest); if( p->org != NULL ) free(p->org); if( p->common_name != NULL ) diff --git a/common/certinfo.h b/common/certinfo.h index d9496bd..ca6f659 100644 --- a/common/certinfo.h +++ b/common/certinfo.h @@ -22,6 +22,7 @@ #define __CERTINFO_H_ typedef struct _certinfo { + char *digest; char *org; char *common_name; char *email; diff --git a/eurephiadm/CMakeLists.txt b/eurephiadm/CMakeLists.txt index d2ae8fd..e538a61 100644 --- a/eurephiadm/CMakeLists.txt +++ b/eurephiadm/CMakeLists.txt @@ -9,6 +9,7 @@ SET(efw_ipt_SRC client_config.c client_context.c client_session.c + parse_certificate_files.c commands/users.c commands/certificates.c commands/edit_config.c @@ -19,6 +20,7 @@ SET(efw_ipt_SRC ../common/eurephia_xml.c ../common/passwd.c ../common/sha512.c + ../common/certinfo.c ../database/eurephiadb.c ) diff --git a/eurephiadm/commands/certificates.c b/eurephiadm/commands/certificates.c index e91dfb4..40e24d1 100644 --- a/eurephiadm/commands/certificates.c +++ b/eurephiadm/commands/certificates.c @@ -29,13 +29,6 @@ #include <errno.h> #include <assert.h> -#ifdef HAVE_OPENSSL -#include <openssl/ssl.h> -#include <openssl/pkcs12.h> -#include <openssl/evp.h> -#include <openssl/err.h> -#endif - #ifdef HAVE_LIBXML2 #include <libxml/parser.h> #include <libxml/tree.h> @@ -52,10 +45,12 @@ #include <eurephia_admin_struct.h> #include <eurephiadb_mapping.h> #include <eurephiadb_driver.h> +#include <certinfo.h> #include "../argparser.h" #include "../get_console_input.h" #include "../field_print.h" +#include "../parse_certificate_files.h" void display_certs_help(int page) { printf("Help page not implemented yet\n"); @@ -82,56 +77,6 @@ int help_Certificates2(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES * return 0; } -#ifdef HAVE_OPENSSL -char *ExtractCertInfo(X509 *cert, const char *fieldname) { - unsigned char *buf = (unsigned char *)1; // Needs to be 1 to avoid OpenSSL 0.9.6b bug - char resbuf[2048]; - X509_NAME *name = NULL; - X509_NAME_ENTRY *namentry = NULL; - ASN1_STRING *asn1 = NULL; - int nid, tmp = -1, pos = -1; - - // - // Extract subject information - // - - memset(&resbuf, 0, 2048); - - nid = OBJ_txt2nid(fieldname); - name = X509_get_subject_name(cert); - - do { - pos = tmp; - tmp = X509_NAME_get_index_by_NID(name, nid, pos); - } while ( tmp > -1 ); - - if( pos == -1 ) { - fprintf(stderr, "%s: Field '%s' not found\n", MODULE, fieldname); - return NULL; - } - - if( !(namentry = X509_NAME_get_entry(name, pos)) ) { - fprintf(stderr, "%s: Failed to extract name entry from field '%s'\n", MODULE, fieldname); - return NULL; - } - - if( !(asn1 = X509_NAME_ENTRY_get_data(namentry)) ) { - fprintf(stderr, "%s: Failed to extract data from name entry field '%s'\n", MODULE, fieldname); - return NULL; - } - - if( ASN1_STRING_to_UTF8(&buf, asn1) <= 0 ) { - fprintf(stderr, "%s: Failed to convert ASN1 string to UTF-8 for '%s'\n", MODULE, fieldname); - return NULL; - } - - snprintf(resbuf, 2046, "%s", buf); - OPENSSL_free(buf); - - return strdup_nullsafe(resbuf); -} -#endif - #define SHOWCERTS_FIREWALL 0x001 #define SHOWCERTS_DIGEST 0x002 @@ -276,7 +221,7 @@ int add_cert(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int a }; certfile = NULL; - certfile_format = 0; + certfile_format = CERTFILE_PEM; // Default file format when not specified for( i = 1; i < argc ; i++ ) { switch( eurephia_getopt(&i, argc, argv, addcertargs) ) { case 'd': // Certificate depth @@ -320,7 +265,7 @@ int add_cert(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int a #ifdef HAVE_OPENSSL case 'p': // Certfile is in PKCS#12 format - certfile_format = 1; + certfile_format = CERTFILE_PKCS12; break; case 'f': // Load certificate info from a certificate file @@ -373,100 +318,22 @@ int add_cert(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int a #ifdef HAVE_OPENSSL // If we have a certfile - open it and fetch the info we want if( certfile != NULL ) { - BIO *bio_err = NULL; - PKCS12 *p12 = NULL; - EVP_PKEY *pkey = NULL; - X509 *cert = NULL; - FILE *fp; - - /* Needed to convert X509 digest into hex string */ - unsigned char md_sha1[EVP_MAX_MD_SIZE]; - unsigned int mdlen; - - if( !bio_err ) { - SSL_library_init(); - SSL_load_error_strings(); - bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - } - - // Open file - according to defined format - switch( certfile_format ) { - case 0: // PEM/DER format - fp = fopen(certfile, "r"); - if( !(cert = PEM_read_X509(fp, NULL, NULL, NULL)) ) { - fprintf(stderr, "%s: Failed to open certificate file\n", MODULE); - return 3; - } - fclose(fp); - break; - - case 1: // PKCS#12 format - fp = fopen(certfile, "r"); - p12 = d2i_PKCS12_fp(fp, NULL); - fclose(fp); - if( p12 == NULL ) { - fprintf(stderr, "%s: Could not open PKCS#12 file\n", MODULE); - return 3; - } - OpenSSL_add_all_ciphers(); - - // First, try without password - if( !PKCS12_parse(p12, "", &pkey, &cert, NULL) ) { - char pwd[130]; - - // If empty password failed, get password and try again - memset(&pwd, 0, 130); - if( get_console_input(pwd, 128, "PKCS12 password:", 1) < 0 ) { - fprintf(stderr, "Could not retrieve password\n"); - } - if( !PKCS12_parse(p12, pwd, &pkey, &cert, NULL) ) { - PKCS12_free(p12); p12 = NULL; - fprintf(stderr, - "%s: Could not open PKCS#12 file - wrong password\n", MODULE); - fprintf(stderr, - "%s: %s\n", MODULE, ERR_error_string(ERR_get_error(), NULL)); - BIO_free(bio_err); - return 3; - } - } - EVP_PKEY_free(pkey); pkey = NULL; - PKCS12_free(p12); p12 = NULL; - break; - - default: // Unknown - fprintf(stderr, "%s: Unknown certificate file format\n", MODULE); - return 1; + certinfo *ci = NULL; + if( (ci = Cert_ParseFile(certfile, certfile_format)) == NULL ) { + fprintf(stderr, "%s: Failed to parse certificate file\n", MODULE); + rc = 1; + goto exit; } + digest = strdup_nullsafe(ci->digest); + cname = strdup_nullsafe(ci->common_name); + org = strdup_nullsafe(ci->org); + email = strdup_nullsafe(ci->email); + free_certinfo(ci); ci = NULL; - - // extract SHA1 digest from certificate - digest = (char *) malloc(66); - memset(digest, 0, 66); - if (X509_digest(cert, EVP_sha1(), md_sha1, &mdlen) && mdlen > 0) { - static const char hexcodes[] = "0123456789ABCDEF"; - int j; - - for (j = 0; j < (int) mdlen; j++) { - digest[j * 3] = hexcodes[(md_sha1[j] & 0xf0) >> 4U]; - digest[(j * 3) + 1] = hexcodes[(md_sha1[j] & 0x0f)]; - if (j + 1 != (int) mdlen) { - digest[(j * 3) + 2] = ':'; - } else { - digest[(j * 3) + 2] = '\0'; - } - } - } - - // Extract the subject information we want - cname = ExtractCertInfo(cert, "CN"); - org = ExtractCertInfo(cert, "O"); - email = ExtractCertInfo(cert, "emailAddress"); - - X509_free(cert); - BIO_free(bio_err); } #endif rc = register_certificate(ctx, depth, digest, cname, org, email); + exit: free_nullsafe(digest); free_nullsafe(cname); free_nullsafe(org); @@ -669,4 +536,3 @@ int cmd_Certificates(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cf return rc; } - diff --git a/eurephiadm/parse_certificate_files.c b/eurephiadm/parse_certificate_files.c new file mode 100644 index 0000000..b2e5ca2 --- /dev/null +++ b/eurephiadm/parse_certificate_files.c @@ -0,0 +1,192 @@ +/* parse_certificate_files.c -- Parses PEM or PKCS12 formated cert. files + * + * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net> + * + * 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; version 2 + * of the License. + * + * 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. + * + */ + +#ifdef HAVE_OPENSSL +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <openssl/ssl.h> +#include <openssl/pkcs12.h> +#include <openssl/evp.h> +#include <openssl/err.h> + +#include <eurephia_nullsafe.h> +#include <certinfo.h> + +#include "get_console_input.h" +#define _PARSE_CERTFICIATE_FILES_C +#include "parse_certificate_files.h" + + +char *ExtractCertInfo(const char *module, X509 *cert, const char *fieldname) { + unsigned char *buf = (unsigned char *)1; // Needs to be 1 to avoid OpenSSL 0.9.6b bug + char resbuf[2050]; + X509_NAME *name = NULL; + X509_NAME_ENTRY *namentry = NULL; + ASN1_STRING *asn1 = NULL; + int nid, tmp = -1, pos = -1; + + // + // Extract subject information + // + + memset(resbuf, 0, 2050); + + nid = OBJ_txt2nid(fieldname); + name = X509_get_subject_name(cert); + + do { + pos = tmp; + tmp = X509_NAME_get_index_by_NID(name, nid, pos); + } while ( tmp > -1 ); + + if( pos == -1 ) { + fprintf(stderr, "%s: Field '%s' not found\n", module, fieldname); + return 0; + } + + if( !(namentry = X509_NAME_get_entry(name, pos)) ) { + fprintf(stderr, "%s: Failed to extract name entry from field '%s'\n", module, fieldname); + return 0; + } + + if( !(asn1 = X509_NAME_ENTRY_get_data(namentry)) ) { + fprintf(stderr, "%s: Failed to extract data from name entry field '%s'\n", module, fieldname); + return 0; + } + + if( ASN1_STRING_to_UTF8(&buf, asn1) <= 0 ) { + fprintf(stderr, "%s: Failed to convert ASN1 string to UTF-8 for '%s'\n", module, fieldname); + return 0; + } + + snprintf(resbuf, 2048, "%s%c", buf, '\0'); + OPENSSL_free(buf); + + return strdup_nullsafe(resbuf); +} + + +certinfo *_Cert_ParseFile(const char *module, const char *certfile, int certfile_format) { + BIO *bio_err = NULL; + PKCS12 *p12 = NULL; + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + FILE *fp; + certinfo *ret = NULL; + + /* Needed to convert X509 digest into hex string */ + unsigned char md_sha1[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + if( !bio_err ) { + SSL_library_init(); + SSL_load_error_strings(); + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + } + + // Open file - according to defined format + switch( certfile_format ) { + case CERTFILE_PEM: // PEM/DER format + fp = fopen(certfile, "r"); + if( !(cert = PEM_read_X509(fp, NULL, NULL, NULL)) ) { + fprintf(stderr, "%s: Failed to open certificate file\n", module); + return NULL; + } + fclose(fp); + break; + + case CERTFILE_PKCS12: // PKCS#12 format + fp = fopen(certfile, "r"); + p12 = d2i_PKCS12_fp(fp, NULL); + fclose(fp); + if( p12 == NULL ) { + fprintf(stderr, "%s: Could not open PKCS#12 file\n", module); + return NULL; + } + OpenSSL_add_all_ciphers(); + + // First, try without password + if( !PKCS12_parse(p12, "", &pkey, &cert, NULL) ) { + char pwd[130]; + + // If empty password failed, get password and try again + memset(&pwd, 0, 130); + if( get_console_input(pwd, 128, "PKCS12 password:", 1) < 0 ) { + fprintf(stderr, "Could not retrieve password\n"); + } + if( !PKCS12_parse(p12, pwd, &pkey, &cert, NULL) ) { + PKCS12_free(p12); p12 = NULL; + fprintf(stderr, + "%s: Could not open PKCS#12 file - wrong password\n", module); + fprintf(stderr, + "%s: %s\n", module, ERR_error_string(ERR_get_error(), NULL)); + BIO_free(bio_err); + return NULL; + } + } + EVP_PKEY_free(pkey); pkey = NULL; + PKCS12_free(p12); p12 = NULL; + break; + + default: // Unknown + fprintf(stderr, "%s: Unknown certificate file format\n", module); + return NULL; + } + + ret = (certinfo *) malloc(sizeof(certinfo)+2); + assert( ret != NULL ); + memset(ret, 0, sizeof(certinfo)+2); + + ret->digest = (char *) malloc(66); + assert(ret != NULL); + memset(ret->digest, 0, 66); + + + + // extract SHA1 digest from certificate + if (X509_digest(cert, EVP_sha1(), md_sha1, &mdlen) && mdlen > 0) { + static const char hexcodes[] = "0123456789ABCDEF"; + int j; + + for (j = 0; j < (int) mdlen; j++) { + ret->digest[j * 3] = hexcodes[(md_sha1[j] & 0xf0) >> 4U]; + ret->digest[(j * 3) + 1] = hexcodes[(md_sha1[j] & 0x0f)]; + if (j + 1 != (int) mdlen) { + ret->digest[(j * 3) + 2] = ':'; + } else { + ret->digest[(j * 3) + 2] = '\0'; + } + } + } + + // Extract the subject information we want + ret->common_name = ExtractCertInfo(module, cert, "CN"); + ret->org = ExtractCertInfo(module, cert, "O"); + ret->email = ExtractCertInfo(module, cert, "emailAddress"); + + X509_free(cert); + BIO_free(bio_err); + + return ret; +} +#endif diff --git a/eurephiadm/parse_certificate_files.h b/eurephiadm/parse_certificate_files.h new file mode 100644 index 0000000..03d66e4 --- /dev/null +++ b/eurephiadm/parse_certificate_files.h @@ -0,0 +1,38 @@ +/* parse_certificate_files.h -- + * + * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net> + * + * 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; version 2 + * of the License. + * + * 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. + * + */ + +#ifndef PARSE_CERTIFICATE_FILES_H_ +# define PARSE_CERTIFICATE_FILES_H_ + +#include <certinfo.h> + +#ifdef HAVE_OPENSSL +#define CERTFILE_PEM 0x01 +#define CERTFILE_PKCS12 0x02 + +#ifndef _PARSE_CERTFICIATE_FILES_C + +#define Cert_ParseFile(cfile,cformat) _Cert_ParseFile(MODULE, cfile, cformat) +certinfo *_Cert_ParseFile(const char *module, const char *certfile, int certfile_format); + +#endif /* !_PARSE_CERTFICIATE_FILES_C */ + +#endif /* HAVE OPENSSL */ +#endif /* !PARSE_CERTIFICATE_FILES_H_ */ |