/*++ /* NAME /* tls_certkey 3 /* SUMMARY /* public key certificate and private key loader /* SYNOPSIS /* #define TLS_INTERNAL /* #include <tls.h> /* /* int tls_set_ca_certificate_info(ctx, CAfile, CApath) /* SSL_CTX *ctx; /* const char *CAfile; /* const char *CApath; /* /* int tls_set_my_certificate_key_info(ctx, chain_files, /* cert_file, key_file, /* dcert_file, dkey_file, /* eccert_file, eckey_file) /* SSL_CTX *ctx; /* const char *chain_files; /* const char *cert_file; /* const char *key_file; /* const char *dcert_file; /* const char *dkey_file; /* const char *eccert_file; /* const char *eckey_file; /* /* int tls_load_pem_chain(ssl, pem, origin); /* SSL *ssl; /* const char *pem; /* const char *origin; /* DESCRIPTION /* OpenSSL supports two options to specify CA certificates: /* either one file CAfile that contains all CA certificates, /* or a directory CApath with separate files for each /* individual CA, with symbolic links named after the hash /* values of the certificates. The second option is not /* convenient with a chrooted process. /* /* tls_set_ca_certificate_info() loads the CA certificate /* information for the specified TLS server or client context. /* The result is -1 on failure, 0 on success. /* /* tls_set_my_certificate_key_info() loads the public key /* certificates and private keys for the specified TLS server /* or client context. Up to 3 pairs of key pairs (RSA, DSA and /* ECDSA) may be specified; each certificate and key pair must /* match. The chain_files argument makes it possible to load /* keys and certificates for more than 3 algorithms, via either /* a single file, or a list of multiple files. The result is -1 /* on failure, 0 on success. /* /* tls_load_pem_chain() loads one or more (key, cert, [chain]) /* triples from an in-memory PEM blob. The "origin" argument /* is used for error logging, to identify the provenance of the /* PEM blob. "ssl" must be non-zero, and the keys and certificates /* will be loaded into that object. /* LICENSE /* .ad /* .fi /* This software is free. You can do with it whatever you want. /* The original author kindly requests that you acknowledge /* the use of his software. /* AUTHOR(S) /* Originally written by: /* Lutz Jaenicke /* BTU Cottbus /* Allgemeine Elektrotechnik /* Universitaetsplatz 3-4 /* D-03044 Cottbus, Germany /* /* Updated by: /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#ifdef USE_TLS
/* Utility library. */
#include <msg.h>
/* Global library. */
#include <mail_params.h>
/* TLS library. */
#define TLS_INTERNAL #include <tls.h>
#define PEM_LOAD_STATE_NOGO -2/* Unusable object or sequence */ #define PEM_LOAD_STATE_FAIL -1/* Error in libcrypto */ #define PEM_LOAD_STATE_DONE 0/* End of PEM file, return value only */ #define PEM_LOAD_STATE_INIT 1/* No PEM objects seen */ #define PEM_LOAD_STATE_PKEY 2/* Last object was a private key */ #define PEM_LOAD_STATE_CERT 3/* Last object was a certificate */ #define PEM_LOAD_STATE_BOTH 4/* Unordered, key + first cert seen */
#define PEM_LOAD_READ_LAST 0/* Reading last file */ #define PEM_LOAD_READ_MORE 1/* More files to be read */
typedefstruct pem_load_state_t { constchar *origin; /* PEM chain origin description */ constchar *source; /* PEM BIO origin description */ constchar *keysrc; /* Source of last key */
BIO *pembio; /* PEM input stream */
SSL_CTX *ctx; /* SSL connection factory */
SSL *ssl; /* SSL connection handle */
EVP_PKEY *pkey; /* current key */
X509 *cert; /* current certificate */
x509_stack_t *chain; /* current chain */ int keynum; /* Index of last key */ int objnum; /* Index in current source */ int state; /* Current state, never "DONE" */ int mixed; /* Single file with key anywhere */
} pem_load_state_t;
/* init_pem_load_state - fill in initial pem_load_state structure */
/* *Whenprocessingthekeyofa"next"chain,we'reinthe"CERT" *state,andfirstcompletetheprocessingofthepreviouschain.
*/ if (!st->mixed && !use_chain(st)) {
msg_warn("error loading certificate chain: " "key at index %d in %s does not match the certificate",
st->keynum, st->keysrc);
st->state = PEM_LOAD_STATE_FAIL; return;
} /* FALLTHROUGH */ case PEM_LOAD_STATE_INIT:
if (!pkey) {
msg_warn("error loading private key (PEM object number %d) from %s",
st->objnum, st->source);
st->state = PEM_LOAD_STATE_FAIL; return;
} /* Reject unexpected data beyond the end of the DER-encoded object */ if (p - buf != buflen) {
msg_warn("error loading private key (PEM object number %d) from" " %s: excess data", st->objnum, st->source);
EVP_PKEY_free(pkey);
st->state = PEM_LOAD_STATE_NOGO; return;
} /* All's well, update the state */
st->pkey = pkey; if (st->state == PEM_LOAD_STATE_INIT)
st->state = PEM_LOAD_STATE_PKEY; elseif (st->mixed)
st->state = PEM_LOAD_STATE_BOTH; else
st->state = PEM_LOAD_STATE_PKEY; return;
case PEM_LOAD_STATE_PKEY: case PEM_LOAD_STATE_BOTH: if (pkey)
EVP_PKEY_free(pkey);
/* XXX: Legacy behavior was silent, should we stay silent? */ if (st->mixed) {
msg_warn("ignoring 2nd key at index %d in %s after 1st at %d",
st->objnum, st->source, st->keynum); return;
} /* else back-to-back keys */
msg_warn("error loading certificate chain: " "key at index %d in %s not followed by a certificate",
st->keynum, st->keysrc);
st->state = PEM_LOAD_STATE_NOGO; return;
/* load_pem_bio - load all key/certs from bio and free the bio */
staticint load_pem_bio(pem_load_state_t *st, int more)
{ int state = st->state;
/* Don't report old news */
ERR_clear_error();
/* *When"more"isPEM_LOAD_READ_MORE,morefileswillbeloadedafterthe *currentfile,andfinalprocessingforthelastkeyandchainis *deferred. * *When"more"isPEM_LOAD_READ_LAST,thisisthelastfileinthelist,and *wevalidatethefinalchain. * *Whenst->mixedistrue,thisistheonlyfile,anditskeycanoccurat *anylocation.Inthiscaseweloadatmostonekey.
*/ for (st->objnum = 1; state > PEM_LOAD_STATE_DONE; ++st->objnum) {
state = load_pem_object(st); if ((st->mixed && st->keynum == 0 &&
(state == PEM_LOAD_STATE_PKEY || state == PEM_LOAD_STATE_BOTH))
|| (!st->mixed && state == PEM_LOAD_STATE_PKEY)) { /* Squirrel-away the current key location */
st->keynum = st->objnum;
st->keysrc = st->source;
}
} /* We're responsible for unconditionally freeing the BIO */
BIO_free(st->pembio);
/* Success with current file, go back for more? */ if (more == PEM_LOAD_READ_MORE && state >= PEM_LOAD_STATE_DONE) return0;
/* *Ifalliswellsofar,completeprocessingforthefinalchain.
*/ switch (st->state) { case PEM_LOAD_STATE_FAIL:
tls_print_errors(); break; default: break; case PEM_LOAD_STATE_INIT:
msg_warn("No PEM data in %s", st->origin); break; case PEM_LOAD_STATE_PKEY:
msg_warn("No certs for key at index %d in %s", st->keynum, st->keysrc); break; case PEM_LOAD_STATE_CERT: if (st->mixed) {
msg_warn("No private key found in %s", st->origin); break;
} /* FALLTHROUGH */ case PEM_LOAD_STATE_BOTH: /* use_chain() frees the key and certs, and zeroes the pointers */ if (use_chain(st)) return (0);
msg_warn("key at index %d in %s does not match next certificate",
st->keynum, st->keysrc);
tls_print_errors(); break;
} /* Free any left-over unused keys and certs */
EVP_PKEY_free(st->pkey);
X509_free(st->cert);
sk_X509_pop_free(st->chain, X509_free);
/* *Weneedboththeprivatekey(inkey_file)andthepublickey *certificate(incert_file). * *CodeadaptedfromOpenSSLapps/s_cb.c.
*/
ERR_clear_error(); if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
msg_warn("cannot get %s certificate from file \"%s\": " "disabling TLS support", cert_type, cert_file);
tls_print_errors(); return (0);
} if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
msg_warn("cannot get %s private key from file \"%s\": " "disabling TLS support", cert_type, key_file);
tls_print_errors(); return (0);
}
/* *Sanitycheck.
*/ if (!SSL_CTX_check_private_key(ctx)) {
msg_warn("%s private key in %s does not match public key in %s: " "disabling TLS support", cert_type, key_file, cert_file); return (0);
} return (1);
}
/* tls_set_my_certificate_key_info - load client or server certificates/keys */
if (key_file)
ret = set_cert_stuff(ctx, "any", argv[0], key_file) == 0; elseif (mixed)
ret = load_mixed_file(ctx, argv[0]); else
ret = load_chain_files(ctx, argv[0]);
if (ret != 0) exit(1);
if (SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST) != 1) {
fprintf(stderr, "error selecting first certificate\n");
tls_print_errors(); exit(1);
} do {
STACK_OF(X509) *chain; int i;
if (SSL_CTX_get0_chain_certs(ctx, &chain) != 1) {
fprintf(stderr, "error locating certificate chain\n");
tls_print_errors(); exit(1);
} for (i = 0; i <= sk_X509_num(chain); ++i) { char buf[CCERT_BUFSIZ];
X509 *cert;
if (i > 0)
cert = sk_X509_value(chain, i - 1); else
cert = SSL_CTX_get0_certificate(ctx);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.