if (auth_retry_get () == AR_NOINTERACT)
sec = 10;
+#if 0 /* not really needed because of c->persist.restart_sleep_seconds */
if (c->options.server_poll_timeout && sec > 1)
sec = 1;
+#endif
#endif
if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec)
to.ns_cert_type = options->ns_cert_type;
memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
to.remote_cert_eku = options->remote_cert_eku;
+ to.verify_hash = options->verify_hash;
to.es = c->c2.es;
#ifdef ENABLE_DEBUG
).
.\"*********************************************************
.TP
+.B --extra-certs file
+Specify a
+.B file
+containing one or more PEM certs (concatenated together)
+that complete the
+local certificate chain.
+
+This option is useful for "split" CAs, where the CA for server
+certs is different than the CA for client certs. Putting certs
+in this file allows them to be used to complete the local
+certificate chain without trusting them to verify the peer-submitted
+certificate, as would be the case if the certs were placed in the
+.B ca
+file.
+.\"*********************************************************
+.TP
.B --key file
Local peer's private key in .pem format. Use the private key which was generated
when you built your peer's certificate (see
.B --key.
.\"*********************************************************
.TP
+.B --verify-hash hash
+Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the
+CA (or intermediate cert) that signs the leaf certificate, and is
+one removed from the leaf certificate in the direction of the root.
+When accepting a connection from a peer, the level-1 cert
+fingerprint must match
+.B hash
+or certificate verification will fail. Hash is specified
+as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
+.\"*********************************************************
+.TP
.B --pkcs11-cert-private [0|1]...
Set if access to certificate object should be performed after login.
Every provider has its own setting.
" Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n"
"--cert file : Local certificate in .pem format -- must be signed\n"
" by a Certificate Authority in --ca file.\n"
+ "--extra-certs file : one or more PEM certs that complete the cert chain.\n"
"--key file : Local private key in .pem format.\n"
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
+ "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n"
#ifdef WIN32
"--cryptoapicert select-string : Load the certificate and private key from the\n"
" Windows Certificate System Store.\n"
return is_persist_option (o) || connection_list_defined (o);
}
+#ifdef USE_SSL
+static uint8_t *
+parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc)
+{
+ int i;
+ const char *cp = str;
+ uint8_t *ret = (uint8_t *) gc_malloc (nbytes, true, gc);
+ char term = 1;
+ int byte;
+ char bs[3];
+
+ for (i = 0; i < nbytes; ++i)
+ {
+ if (strlen(cp) < 2)
+ msg (msglevel, "format error in hash fingerprint: %s", str);
+ bs[0] = *cp++;
+ bs[1] = *cp++;
+ bs[2] = 0;
+ byte = 0;
+ if (sscanf(bs, "%x", &byte) != 1)
+ msg (msglevel, "format error in hash fingerprint hex byte: %s", str);
+ ret[i] = (uint8_t)byte;
+ term = *cp++;
+ if (term != ':' && term != 0)
+ msg (msglevel, "format error in hash fingerprint delimiter: %s", str);
+ if (term == 0)
+ break;
+ }
+ if (term != 0 || i != nbytes-1)
+ msg (msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str);
+ return ret;
+}
+#endif
+
#ifdef WIN32
#ifdef ENABLE_DEBUG
}
#endif
}
+ else if (streq (p[0], "extra-certs") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->extra_certs_file = p[1];
+#if ENABLE_INLINE_FILES
+ if (streq (p[1], INLINE_FILE_TAG) && p[2])
+ {
+ options->extra_certs_file_inline = p[2];
+ }
+#endif
+ }
+ else if (streq (p[0], "verify-hash") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
+ }
#ifdef WIN32
else if (streq (p[0], "cryptoapicert") && p[1])
{
const char *ca_path;
const char *dh_file;
const char *cert_file;
+ const char *extra_certs_file;
const char *priv_key_file;
const char *pkcs12_file;
const char *cipher_list;
#if ENABLE_INLINE_FILES
const char *ca_file_inline;
const char *cert_file_inline;
+ const char *extra_certs_file_inline;
char *priv_key_file_inline;
const char *dh_file_inline;
const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
+ uint8_t *verify_hash;
#ifdef ENABLE_PKCS11
const char *pkcs11_providers[MAX_PARMS];
goto err; /* Reject connection */
}
+ /* verify level 1 cert, i.e. the CA that signed our leaf cert */
+ if (ctx->error_depth == 1 && opt->verify_hash)
+ {
+ if (memcmp (ctx->current_cert->sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
+ goto err;
+ }
+ }
+
/* save common name in session object */
if (ctx->error_depth == 0)
set_common_name (session, common_name);
msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", options->cert_file);
}
+ /* Load extra certificates that are part of our own certificate
+ chain but shouldn't be included in the verify chain */
+ if (options->extra_certs_file || options->extra_certs_file_inline)
+ {
+ BIO *bio;
+ X509 *cert;
+#if ENABLE_INLINE_FILES
+ if (!strcmp (options->extra_certs_file, INLINE_FILE_TAG) && options->extra_certs_file_inline)
+ {
+ bio = BIO_new_mem_buf ((char *)options->extra_certs_file_inline, -1);
+ }
+ else
+#endif
+ {
+ bio = BIO_new(BIO_s_file());
+ if (BIO_read_filename(bio, options->extra_certs_file) <= 0)
+ msg (M_SSLERR, "Cannot load extra-certs file: %s", options->extra_certs_file);
+ }
+ for (;;)
+ {
+ cert = NULL;
+ if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */
+ break;
+ if (!cert)
+ msg (M_SSLERR, "Error reading extra-certs certificate");
+ if (SSL_CTX_add_extra_chain_cert(ctx, cert) != 1)
+ msg (M_SSLERR, "Error adding extra-certs certificate");
+ }
+ BIO_free (bio);
+ }
+
/* Require peer certificate verification */
#if P2MP_SERVER
if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
int ns_cert_type;
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
+ uint8_t *verify_hash;
/* allow openvpn config info to be
passed over control channel */
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3u])
+define(PRODUCT_VERSION,[2.1.3v])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])