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 /eurephiadm/parse_certificate_files.c | |
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.
Diffstat (limited to 'eurephiadm/parse_certificate_files.c')
-rw-r--r-- | eurephiadm/parse_certificate_files.c | 192 |
1 files changed, 192 insertions, 0 deletions
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 |