blob: 7b53770e1eab6c3cd9adcd9228c16370185ccc57 [file] [log] [blame]
char *cksslv = "SSL/TLS support, 8.0.221, 26 Feb 2004";
/*
C K _ S S L . C -- OpenSSL Interface for C-Kermit
Copyright (C) 1985, 2004,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
Author: Jeffrey E Altman (jaltman@secure-endpoints.com)
Secure Endpoints Inc., New York City
Provides:
. Telnet Auth SSL option compatible with Tim Hudson's hack.
. Telnet START_TLS option
. Configuration of certificate and key files
. Certificate verification and revocation list checks
. Client certificate to user id routine
Note: This code is written to be compatible with OpenSSL 0.9.6[abcdefgh]
and 0.9.7 beta 5.
It will also compile with version 0.9.5 although that is discouraged
due to security weaknesses in that release.
*/
#include "ckcsym.h"
#include "ckcdeb.h"
#ifdef CK_SSL
#include "ckcnet.h"
#include "ckuath.h"
#include <stdlib.h>
#include <string.h>
#ifdef UNIX
#include <netinet/in.h>
#ifndef FREEBSD4
#include <arpa/inet.h>
#endif /* FREEBSD4 */
#endif /* UNIX */
#ifdef DEC_TCPIP
#include <time.h>
#include <inet.h>
#endif /* DEC_TCPIP */
#ifdef OS2
extern char exedir[];
#ifdef NT
char * GetAppData(int);
#endif
#endif /* OS2 */
static int ssl_installed = 1;
#endif /* CK_SSL */
int
ck_ssh_is_installed()
{
#ifdef SSHBUILTIN
#ifdef SSLDLL
#ifdef NT
extern HINSTANCE hCRYPTO;
#else /* NT */
extern HMODULE hCRYPTO;
#endif /* NT */
debug(F111,"ck_ssh_is_installed","hCRYPTO",hCRYPTO);
return(ssl_installed && (hCRYPTO != NULL));
#else /* SSLDLL */
return(ssl_installed);
#endif /* SSLDLL */
#else
return 0;
#endif
}
int
#ifdef CK_ANSIC
ck_ssleay_is_installed(void)
#else
ck_ssleay_is_installed()
#endif
{
#ifdef CK_SSL
#ifdef SSLDLL
#ifdef NT
extern HINSTANCE hSSL, hCRYPTO;
#else /* NT */
extern HMODULE hSSL, hCRYPTO;
#endif /* NT */
debug(F111,"ck_ssleay_is_installed","hSSL",hSSL);
debug(F111,"ck_ssleay_is_installed","hCRYPTO",hCRYPTO);
return(ssl_installed && (hSSL != NULL) && (hCRYPTO != NULL));
#else /* SSLDLL */
return(ssl_installed);
#endif /* SSLDLL */
#else /* CK_SSL */
return(0);
#endif /* CK_SSL */
}
#ifdef CK_SSL
#include "ckcker.h"
#include "ckucmd.h" /* For struct keytab */
#include "ckctel.h"
#include "ck_ssl.h"
#ifdef UNIX
#include <pwd.h> /* Password file for home directory */
#endif /* UNIX */
#ifdef OS2
#include <process.h>
#endif /* OS2 */
#ifdef OS2ONLY
#include "ckotcp.h"
#endif /* OS2ONLY */
#ifdef SSLDLL
int ssl_finished_messages = 0;
#else /* SSLDLL */
#ifdef OPENSSL_VERSION_NUMBER
int ssl_finished_messages = (OPENSSL_VERSION_NUMBER >= 0x0090581fL);
#else
!ERROR This module requires OpenSSL 0.9.5a or higher
#endif /* OPENSSL_VERSION_NUMBER */
#endif /* SSLDLL */
static int auth_ssl_valid = 0;
static char *auth_ssl_name = 0; /* this holds the oneline name */
char ssl_err[SSL_ERR_BFSZ]="";
BIO *bio_err=NULL;
X509_STORE *crl_store = NULL;
#ifndef NOFTP
#ifndef SYSFTP
SSL *ssl_ftp_con = NULL;
SSL_CTX *ssl_ftp_ctx = NULL;
SSL *ssl_ftp_data_con = NULL;
int ssl_ftp_active_flag = 0;
int ssl_ftp_data_active_flag = 0;
#endif /* SYSFTP */
#endif /* NOFTP */
#ifndef NOHTTP
SSL *tls_http_con = NULL;
SSL_CTX *tls_http_ctx = NULL;
int tls_http_active_flag = 0;
int ssl_http_initialized = 0;
#endif /* NOHTTP */
SSL_CTX *ssl_ctx = NULL;
SSL *ssl_con = NULL;
int ssl_debug_flag = 0;
int ssl_verbose_flag = 0;
int ssl_only_flag = 0;
int ssl_active_flag = 0;
int ssl_verify_flag = SSL_VERIFY_PEER;
int ssl_certsok_flag = 0;
char *ssl_rsa_cert_file = NULL;
char *ssl_rsa_cert_chain_file = NULL;
char *ssl_rsa_key_file = NULL;
char *ssl_dsa_cert_file = NULL;
char *ssl_dsa_cert_chain_file = NULL;
char *ssl_dh_key_file = NULL;
char *ssl_crl_file = NULL;
char *ssl_crl_dir = NULL;
char *ssl_verify_file = NULL;
char *ssl_verify_dir = NULL;
char *ssl_dh_param_file = NULL;
char *ssl_cipher_list = NULL;
char *ssl_rnd_file = NULL;
SSL_CTX *tls_ctx = NULL;
SSL *tls_con = NULL;
int tls_only_flag = 0;
int tls_active_flag = 0;
int ssl_initialized = 0;
int ssl_verify_depth = -1; /* used to track depth in verify routines */
/* compile this set to 1 to negotiate SSL/TLS but not actually start it */
int ssl_dummy_flag=0;
extern int inserver;
extern int debses;
extern int accept_complete;
extern char szHostName[], szUserNameRequested[], szUserNameAuthenticated[];
_PROTOTYP(int X509_to_user,(X509 *, char *, int));
int
#ifdef CK_ANSIC
ssl_server_verify_callback(int ok, X509_STORE_CTX * ctx)
#else /* CK_ANSIC */
ssl_server_verify_callback(ok, ctx)
int ok;
X509_STORE_CTX *ctx;
#endif /* CK_ANSIC */
{
static char *saved_subject=NULL;
char *subject=NULL, *issuer=NULL;
int depth,error;
X509 *xs = NULL;
if ( ssl_certsok_flag )
return(1);
error=X509_STORE_CTX_get_error(ctx);
depth=X509_STORE_CTX_get_error_depth(ctx);
xs=X509_STORE_CTX_get_current_cert(ctx);
if (depth==0) {
/* clear things */
if (saved_subject!=NULL) {
free(saved_subject);
saved_subject=NULL;
}
if (auth_ssl_name!=NULL) {
free(auth_ssl_name);
auth_ssl_name=NULL;
}
}
if (ssl_debug_flag && !inserver) {
printf("ssl:server_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
depth,ok,error,X509_verify_cert_error_string(error));
}
/* first thing is to have a meaningful name for the current
* certificate that is being verified ... and if we cannot
* determine that then something is seriously wrong!
*/
makestr(&subject,
(char *)X509_NAME_oneline(X509_get_subject_name(xs),NULL,0));
makestr(&issuer,
(char *)X509_NAME_oneline(X509_get_issuer_name(xs),NULL,0));
if (!subject || !subject[0] || !issuer || !issuer[0]) {
ok = 0;
goto return_time;
}
if (ssl_verbose_flag && !inserver && depth != ssl_verify_depth) {
printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
ssl_verify_depth = depth;
}
/* make sure that the certificate that has been presented */
/* has not been revoked (if we have been given a CRL. */
ok = ssl_verify_crl(ok, ctx);
/* if we have any form of error in secure mode we reject the connection */
if (error!=X509_V_OK) {
if (inserver) {
#ifdef CKSYSLOG
if (ckxsyslog >= SYSLG_LI && ckxlogging) {
cksyslog(SYSLG_LI, 0,
"X.509 Certificate verify failure",
(char *) subject,
(char *)X509_verify_cert_error_string(error)
);
}
#endif /* CKSYSLOG */
} else {
if ( ssl_verify_flag &
(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
printf("Error: ");
else
printf("Warning: ");
switch (error) {
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
printf("Certificate is self signed.\r\n");
break;
case X509_V_ERR_CERT_HAS_EXPIRED:
printf("Certificate has expired.\r\n");
break;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
printf(
"Certificate issuer's certificate isn't available locally.\r\n");
break;
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
printf("Unable to verify leaf signature.\r\n");
break;
case X509_V_ERR_CERT_REVOKED:
printf("Certificate revoked.\r\n");
break;
default:
printf("Error %d while verifying certificate.\r\n",
ctx->error);
break;
}
}
ok = !(ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
} else {
/* if we got all the way to the top of the tree then
* we *can* use this certificate for a username to
* match ... in all other cases we must not!
*/
auth_ssl_name = saved_subject;
saved_subject = NULL;
}
return_time:
/* save the name if at least the first level is okay */
if (depth == 0 && ok)
makestr(&saved_subject,subject);
/* clean up things */
if (subject!=NULL)
free(subject);
if (issuer!=NULL)
free(issuer);
return ok;
}
int
#ifdef CK_ANSIC
ssl_client_verify_callback(int ok, X509_STORE_CTX * ctx)
#else
ssl_client_verify_callback(ok, ctx)
int ok;
X509_STORE_CTX *ctx;
#endif
{
char subject[256]="", issuer[256]="";
int depth, error, len;
X509 *xs;
xs=X509_STORE_CTX_get_current_cert(ctx);
error=X509_STORE_CTX_get_error(ctx);
depth=X509_STORE_CTX_get_error_depth(ctx);
if ( ssl_debug_flag )
printf("ssl:client_verify_callback:depth=%d ok=%d err=%d-%s\r\n",
depth,ok,error,X509_verify_cert_error_string(error));
if ( ssl_certsok_flag ) {
ok = 1;
}
/* first thing is to have a meaningful name for the current
* certificate that is being verified ... and if we cannot
* determine that then something is seriously wrong!
*/
#ifdef XN_FLAG_SEP_MULTILINE
X509_NAME_print_ex(bio_err,X509_get_subject_name(xs),4,
XN_FLAG_SEP_MULTILINE);
len = BIO_read(bio_err,subject,256);
subject[len < 256 ? len : 255] = '\0';
if (!subject[0]) {
ERR_print_errors(bio_err);
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
ok=0;
goto return_time;
}
X509_NAME_print_ex(bio_err,X509_get_issuer_name(xs),4,
XN_FLAG_SEP_MULTILINE);
len = BIO_read(bio_err,issuer,256);
issuer[len < 256 ? len : 255] = '\0';
if (!issuer[0]) {
ERR_print_errors(bio_err);
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
ok=0;
goto return_time;
}
#else /* XN_FLAG_SEP_MULTILINE */
X509_NAME_oneline(X509_get_subject_name(xs),subject,256);
if (!subject[0]) {
int len;
ERR_print_errors(bio_err);
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0);
ok=0;
goto return_time;
}
X509_NAME_oneline(X509_get_issuer_name(xs),issuer,256);
if (!issuer[0]) {
int len;
ERR_print_errors(bio_err);
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0);
ok=0;
goto return_time;
}
#endif /* XN_FLAG_SEP_MULTILINE */
if (ssl_verbose_flag && depth != ssl_verify_depth) {
printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject);
printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer);
ssl_verify_depth = depth;
}
ok = ssl_verify_crl(ok, ctx);
if ( !ok ) {
char prefix[1024];
/* if the server is using a self signed certificate then
* we need to decide if that is good enough for us to
* accept ...
*/
switch ( error ) {
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: {
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
/* make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
ckmakxmsg(prefix,1024,
"Error: Server has a self-signed certificate\n",
"[",ckitoa(depth),"] Certificate Subject=\n",subject,
"\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
ckmakxmsg(prefix,1024,
"Warning: Server has a self-signed certificate\n",
"[",ckitoa(depth),"] Certificate Subject=\n",subject,
"\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer,
NULL,NULL,NULL);
ok = uq_ok(prefix,
"Continue? (Y/N) ",
3, NULL, 0);
if ( ok < 0 )
ok = 0;
goto return_time;
}
}
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
/* make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
ckmakxmsg(prefix,1024,
"Error: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Issuer=\n",issuer,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
ckmakxmsg(prefix,1024,
"Warning: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Issuer=\n",issuer,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
goto return_time;
}
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
int len;
/* make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
ckmakxmsg(prefix,1024,
"Error: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
"\nnotBefore=",ssl_err,
NULL,NULL,NULL,NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
int len;
ASN1_TIME_print(bio_err,X509_get_notBefore(xs));
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
ckmakxmsg(prefix,1024,
"Warning: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
"\n notBefore=",ssl_err,
NULL,NULL,NULL,NULL,NULL,NULL);
ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
}
break;
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
int len;
/* make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
ckmakxmsg(prefix,1024,
"Error: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
"\n notAfter=",ssl_err,
NULL,NULL,NULL,NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
int len;
ASN1_TIME_print(bio_err,X509_get_notAfter(xs));
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
ckmakxmsg(prefix,1024,
"Warning: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
"\n notAfter=",ssl_err,
NULL,NULL,NULL,NULL,NULL,NULL);
ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
}
break;
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
/*
* When an SSL server sends its certificates to the client there
* are two" conventions": one is to send the complete certificate
* chain and the other is to send the whole chain apart from the
* root.
*
* You don't usually need the root because the root is normally
* stored and trusted locally.
*
* So if you get the whole chain it will complain about the self
* signed certificate whereas if the root is missing it says it
* can't find the issuer certificate.
*/
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
/* make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
ckmakxmsg(prefix,1024,
"Error: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Issuer=\n",issuer,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
ckmakxmsg(prefix,1024,
"Warning: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Issuer=\n",issuer,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
#ifdef NT
if (ok) {
/* if the user decides to accept the certificate
* offer to store it for future connections in
* the user's private store
*/
ok = uq_ok(
"Do you wish to store the certificate to verify future connections?",
"Continue (Y/N)", 3, NULL, 0);
if (ok)
ck_X509_save_cert_to_user_store(xs);
}
#endif /* NT */
}
break;
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CRL_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
case X509_V_ERR_OUT_OF_MEM:
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
case X509_V_ERR_CERT_REVOKED:
case X509_V_ERR_APPLICATION_VERIFICATION:
default:
if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
/* make 100% sure that in secure mode we drop the
* connection if the server does not have a
* real certificate!
*/
ckmakxmsg(prefix,1024,
"Error: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
uq_ok(prefix, "Rejecting Connection", 1, NULL, 0);
/* sometimes it is really handy to be able to debug things
* and still get a connection!
*/
if (ssl_debug_flag) {
printf("SSL: debug -> ignoring cert required!\r\n");
ok=1;
} else {
ok=0;
}
goto return_time;
} else if (ssl_verify_flag != SSL_VERIFY_NONE) {
ckmakxmsg(prefix,1024,
"Warning: ",
(char *)X509_verify_cert_error_string(error),
"\nCertificate Subject=\n",subject,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0);
}
break;
}
}
return_time:
if ( ssl_debug_flag )
printf("ssl:client_verify_callback => ok: %d\r\n",ok);
return ok;
}
VOID
#ifdef CK_ANSIC
ssl_client_info_callback(const SSL *s, int where, int ret)
#else
ssl_client_info_callback(s,where,ret)
const SSL *s;
int where;
int ret;
#endif /* CK_ANSIC */
{
if (inserver || !ssl_debug_flag)
return;
switch ( where ) {
case SSL_CB_CONNECT_LOOP:
printf("SSL_connect:%s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
break;
case SSL_CB_CONNECT_EXIT:
if (ret == 0) {
printf("SSL_connect:failed in %s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
} else if (ret < 0) {
printf("SSL_connect:error in %s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
}
break;
case SSL_CB_ACCEPT_LOOP:
printf("SSL_accept:%s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
break;
case SSL_CB_ACCEPT_EXIT:
if (ret == 0) {
printf("SSL_accept:failed in %s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
} else if (ret < 0) {
printf("SSL_accept:error in %s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
}
break;
case SSL_CB_READ_ALERT:
printf("SSL_read_alert\r\n");
break;
case SSL_CB_WRITE_ALERT:
printf("SSL_write_alert\r\n");
break;
case SSL_CB_HANDSHAKE_START:
printf("SSL_handshake:%s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
break;
case SSL_CB_HANDSHAKE_DONE:
printf("SSL_handshake:%s %s\r\n",
SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s));
break;
}
}
#ifdef USE_CERT_CB
/* Return 1, client cert is available */
/* Return 0, no client cert is available */
/* Return -1, callback must be called again. SSL_want_x509_lookup() == 1 */
int
#ifdef CK_ANSIC
ssl_client_cert_callback(SSL * s, X509 ** x509, EVP_PKEY ** pkey)
#else /* CK_ANSIC */
ssl_client_cert_callback(s, x509, pkey)
SSL * s;
X509 ** x509;
EVP_PKEY ** pkey;
#endif /* CK_ANSIC */
{
if ( ssl_debug_flag ) {
const char * cipher_list=SSL_get_cipher(s);
printf("ssl_client_cert_callback called (%s)\r\n",
cipher_list?cipher_list:"UNKNOWN");
}
#ifdef COMMENT
if ( s == tls_con ) {
if (tls_load_certs(tls_cts,tls_con,0)) {
*x509 = SSL_get_certificate(s);
*pkey = SSL_get_privatekey(s);
return(1);
}
} else if ( s == ssl_con ) {
if (tls_load_certs(ssl_ctx,ssl_con,0)) {
*x509 = SSL_get_certificate(s);
*pkey = SSL_get_privatekey(s);
return(1);
}
}
return(0);
#else /* COMMENT */
return(0);
#endif /* COMMENT */
}
#endif /* USE_CERT_CB */
#ifndef MS_CALLBACK
#define MS_CALLBACK
#endif /* MS_CALLBACK */
static RSA MS_CALLBACK *
#ifdef CK_ANSIC
tmp_rsa_cb(SSL * s, int export, int keylength)
#else /* CK_ANSIC */
tmp_rsa_cb(s,export,keylength)
SSL *s;
int export;
int keylength;
#endif /* CK_ANSIC */
{
static RSA *rsa_tmp=NULL;
extern int quiet;
#ifndef NO_RSA
if (rsa_tmp == NULL)
{
if (ssl_debug_flag)
printf("Generating temporary (%d bit) RSA key...\r\n",keylength);
rsa_tmp=RSA_generate_key(keylength,RSA_F4,NULL,NULL);
if (ssl_debug_flag)
printf("\r\n");
}
#else /* NO_RSA */
if (ssl_debug_flag)
printf("Unable to generate temporary RSA key...\r\n");
#endif
return(rsa_tmp);
}
#ifndef NO_DH
static unsigned char dh512_p[]={
0xE9,0x4E,0x3A,0x64,0xFA,0x65,0x5F,0xA6,0x44,0xC7,0xFC,0xF1,
0x16,0x8B,0x11,0x11,0x7A,0xF0,0xB2,0x49,0x80,0x56,0xA3,0xF8,
0x0F,0x7D,0x01,0x68,0x5D,0xF6,0x8A,0xEA,0x8C,0xDD,0x01,0xDC,
0x43,0x18,0xE0,0xC4,0x89,0x80,0xE6,0x2D,0x44,0x77,0x45,0xFD,
0xBA,0xFC,0x43,0x35,0x12,0xC0,0xED,0x32,0xD3,0x16,0xEF,0x51,
0x09,0x44,0xA2,0xDB,
};
static unsigned char dh512_g[]={
0x05,
};
static unsigned char dh768_p[]={
0x8B,0x2A,0x8C,0x6C,0x0F,0x87,0xC7,0x34,0xEE,0x2E,0xFB,0x60,
0x94,0xB3,0xBF,0x95,0xBA,0x84,0x74,0x86,0xEA,0xE0,0xA4,0x33,
0xE0,0x8F,0x7C,0x79,0x5C,0x62,0xE2,0x91,0xC5,0x6D,0x68,0xB9,
0x6C,0x5E,0x4E,0x94,0x0C,0x8E,0x56,0x8E,0xEB,0x98,0x7C,0x6E,
0x0E,0xF2,0xD5,0xAA,0x22,0x27,0x3F,0x0F,0xAF,0x10,0xB5,0x0B,
0x16,0xCC,0x05,0x27,0xBB,0x58,0x6D,0x61,0x4B,0x2B,0xAB,0xDC,
0x6A,0x15,0xBC,0x36,0x75,0x4D,0xEC,0xAB,0xFA,0xB6,0xE1,0xB1,
0x13,0x70,0xD8,0x77,0xCD,0x5E,0x51,0x77,0x81,0x0D,0x77,0x43,
};
static unsigned char dh768_g[]={
0x05,
};
static unsigned char dh1024_p[]={
0xA4,0x75,0xCF,0x35,0x00,0xAF,0x3C,0x17,0xCE,0xB0,0xD0,0x52,
0x43,0xA0,0x0E,0xFA,0xA2,0xC9,0xBE,0x0B,0x76,0x7A,0xD9,0x2E,
0xF4,0x97,0xAC,0x02,0x24,0x69,0xF6,0x36,0x4F,0xAB,0xCC,0x43,
0xC1,0x74,0xFF,0xA3,0xD4,0x04,0x0F,0x11,0x2B,0x6D,0x8C,0x47,
0xC9,0xCF,0x40,0x93,0x9B,0x7D,0x1E,0x52,0x85,0xB2,0x17,0x55,
0x9C,0xF2,0x41,0x02,0x2A,0x9D,0x5F,0x24,0x22,0xC6,0x04,0xC4,
0xAB,0x92,0x6D,0xC7,0xC8,0xF3,0x41,0x58,0x6C,0x86,0xFD,0xB8,
0x0F,0x2D,0xDD,0xBF,0xA8,0x40,0x0C,0x58,0xC8,0xF2,0x3F,0x18,
0xEF,0xF1,0x93,0x3E,0xBA,0x16,0x41,0xBE,0x32,0x6C,0xC5,0x63,
0xFF,0x8A,0x02,0x3D,0xAC,0xD5,0x5A,0x49,0x64,0x34,0x14,0x2E,
0xFB,0x2E,0xE7,0x39,0x1A,0x0F,0x3C,0x33,
};
static unsigned char dh1024_g[]={
0x05,
};
static unsigned char dh1536_p[]={
0xA3,0x2B,0x75,0x0E,0x7B,0x31,0x82,0xCA,0xF2,0xFC,0xF3,0x3D,
0xCE,0x5F,0xCD,0x5B,0x95,0xF6,0x2F,0xA4,0x5D,0x08,0x26,0xD2,
0x5F,0xC0,0x3F,0xC5,0xD8,0xA2,0xFE,0x83,0x26,0xBC,0xEB,0x7D,
0xF0,0x4E,0xD2,0xA6,0xBB,0x3C,0x88,0x63,0xCE,0x98,0xDE,0x08,
0xE2,0xE1,0xAF,0xE2,0x38,0xA8,0xFA,0x68,0x76,0x8D,0xBF,0xDF,
0xBB,0x30,0x15,0xFE,0xBD,0x22,0xCC,0x03,0x4E,0x5E,0x33,0xA3,
0x6D,0xD6,0x68,0x12,0x97,0x17,0x4B,0xB5,0x84,0x5F,0x5F,0xA3,
0x5C,0x2F,0xA4,0x10,0xC1,0xAD,0xBF,0xAC,0x30,0xCA,0x47,0x64,
0x63,0xFE,0xEE,0xEE,0xA1,0x64,0x73,0x70,0xAA,0xF9,0xFE,0xC6,
0xAD,0x5E,0xF6,0xF3,0x9C,0xDF,0x34,0x53,0x34,0x72,0xA6,0xA4,
0xBB,0x81,0x5A,0x43,0x41,0xFD,0x41,0x05,0x5B,0x77,0x7B,0x84,
0x03,0xFA,0x8A,0xFA,0xF7,0x8E,0x0F,0xCB,0x51,0xA2,0xB8,0x45,
0xFF,0x59,0x42,0xEF,0xCF,0xF6,0x25,0x37,0xE2,0x6D,0xFF,0x69,
0x11,0xF5,0x77,0x59,0x79,0x1C,0x5F,0x05,0xFC,0x7A,0x65,0x81,
0x03,0x4A,0x78,0xC6,0xE9,0x48,0x73,0xF6,0x10,0xBC,0x99,0x1C,
0xEE,0x44,0x2F,0x8B,0x70,0xCA,0xA8,0xB6,0x02,0x83,0x3E,0x0B,
};
static unsigned char dh1536_g[]={
0x05,
};
static unsigned char dh2048_p[]={
0xFA,0x4E,0xE4,0x3B,0xFA,0xC1,0x87,0xDD,0xE7,0xC6,0x8B,0xE6,
0x13,0x85,0xBC,0x9B,0x2B,0x8B,0x5B,0x46,0xBB,0x8B,0x86,0x6D,
0xD7,0xB6,0xD5,0x49,0xC5,0x54,0xF2,0x3E,0xD2,0x39,0x64,0x9B,
0x0E,0x33,0x39,0x8F,0xFA,0xFA,0xD9,0x78,0xED,0x34,0x82,0x29,
0x37,0x58,0x4D,0x5D,0x40,0xCB,0x69,0xE3,0x8A,0x9F,0x17,0x0C,
0x01,0x23,0x6B,0x05,0x01,0xAF,0x33,0xDE,0xDF,0x1A,0xBB,0x7B,
0x6A,0x9F,0xD8,0xED,0x8D,0x5E,0x44,0x19,0x5B,0xE0,0xB6,0x23,
0xF9,0x7A,0x96,0x6E,0x94,0x33,0x31,0x49,0xBA,0x84,0xD5,0x12,
0xD7,0x6D,0xDC,0x35,0x54,0x64,0xA3,0xD8,0x04,0x26,0xC5,0xAF,
0x7F,0xE3,0xFE,0x6F,0xBE,0xD5,0x17,0x72,0x4B,0xA6,0xD0,0xA7,
0x5F,0x18,0xF5,0xF0,0x2D,0x11,0x9A,0xF6,0xD5,0x3B,0x6C,0x61,
0x3C,0x6F,0x8E,0x09,0x4F,0x2C,0xE1,0x26,0x06,0x51,0xB3,0x19,
0x85,0x85,0x13,0xF9,0xC2,0x6E,0x80,0x28,0x9E,0x8A,0xA0,0x01,
0x46,0xD1,0x85,0x44,0x8C,0xE6,0xEE,0x7E,0x1E,0x17,0x3D,0xBA,
0x54,0xFF,0xE8,0x0E,0xDD,0x51,0xF3,0x74,0x7F,0x0D,0x0B,0xAB,
0xCA,0x84,0x8D,0x24,0x5D,0x56,0xD4,0x47,0x02,0xFC,0x93,0x9F,
0xAE,0x9B,0x5C,0xDB,0x63,0xEB,0x65,0x01,0x38,0xC2,0x7B,0x30,
0x1E,0x17,0x1C,0x75,0xF5,0x16,0x3B,0x4F,0x5F,0x41,0x32,0xB5,
0xFF,0x9E,0x61,0xFD,0xD2,0x62,0x6E,0xFD,0x8A,0x28,0x93,0x59,
0x2D,0x70,0x14,0x4D,0xE1,0x86,0xD5,0x90,0xB4,0xDF,0x72,0x71,
0xE0,0xB4,0xD0,0xD6,0x82,0x3A,0x4A,0x04,0x58,0x32,0x0B,0xD3,
0x51,0x13,0x32,0x63,
};
static unsigned char dh2048_g[]={
0x02,
};
static DH *
get_dh512()
{
DH *dh=NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
static DH *
get_dh768()
{
DH *dh=NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL);
dh->g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
static DH *
get_dh1024()
{
DH *dh=NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
static DH *
get_dh1536()
{
DH *dh=NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL);
dh->g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
static DH *
get_dh2048()
{
DH *dh=NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
#endif /* NO_DH */
static DH MS_CALLBACK *
#ifdef CK_ANSIC
tmp_dh_cb(SSL * s, int export, int keylength)
#else /* CK_ANSIC */
tmp_dh_cb(s,export,keylength)
SSL *s;
int export;
int keylength;
#endif /* CK_ANSIC */
{
static DH *dh_tmp=NULL;
BIO *bio=NULL;
extern int quiet;
#ifndef NO_DH
if (dh_tmp == NULL)
{
if (ssl_dh_param_file &&
(bio=BIO_new_file(ssl_dh_param_file,"r")) != NULL)
dh_tmp=PEM_read_bio_DHparams(bio,NULL,NULL,NULL);
if (bio != NULL)
BIO_free(bio);
if ( dh_tmp == NULL ) {
if ( keylength < 768 )
dh_tmp = get_dh512();
else if ( keylength < 1024 )
dh_tmp = get_dh768();
else if ( keylength < 1536 )
dh_tmp = get_dh1024();
else if ( keylength < 2048 )
dh_tmp = get_dh1536();
else
dh_tmp = get_dh2048();
}
}
#else /* NO_DH */
if (ssl_debug_flag)
printf("DH not supported...\r\n");
#endif /* NO_DH */
return(dh_tmp);
}
static void
ssl_display_comp(SSL * ssl)
{
if ( !ck_ssleay_is_installed() )
return;
if (ssl == NULL)
return;
if (ssl->expand == NULL || ssl->expand->meth == NULL)
printf("Compression: None\r\n");
else {
printf("Compression: %s\r\n",ssl->expand->meth->name);
}
}
int
#ifdef CK_ANSIC
ssl_display_connect_details(SSL * ssl_con, int server, int verbose)
#else /* CK_ANSIC */
ssl_display_connect_details(ssl_con,server,verbose)
SSL *ssl_con;
int server;
int verbose;
#endif /* CK_ANSIC */
{
X509 *peer;
SSL_CIPHER * cipher;
const char *cipher_list;
char buf[512]="";
if ( !ck_ssleay_is_installed() )
return(0);
if ( inserver && !tn_deb )
return(0);
/* the cipher list *can* be NULL ... useless but it happens! */
cipher = SSL_get_current_cipher(ssl_con);
cipher_list = SSL_CIPHER_get_name(cipher);
SSL_CIPHER_description(cipher,buf,sizeof(buf));
if (cipher_list==NULL)
cipher_list="<NULL>";
printf("[TLS - %s",buf);
ssl_display_comp(ssl_con);
if ( server ) {
cipher_list=SSL_get_shared_ciphers(ssl_con,buf,512);
if (cipher_list==NULL)
cipher_list="<NULL>";
printf("[TLS - shared ciphers=%s]\r\n",
cipher_list);
}
if ( server || tn_deb ) {
peer=SSL_get_peer_certificate(ssl_con);
if (peer != NULL) {
X509_NAME_oneline(X509_get_subject_name(peer),buf,512);
printf("[TLS - subject=%s]\r\n",buf);
X509_NAME_oneline(X509_get_issuer_name(peer),buf,512);
printf("[TLS - issuer=%s]\r\n",buf);
/* X509_free(peer); */
} else if (!tls_is_krb5(0)) {
if ( !sstelnet && !tcp_incoming ) {
printf("[TLS - No certificate provided.]\r\n");
printf(
"[TLS - The identity of the host could not be verified.]\r\n");
}
}
}
return(0);
}
/*
* Use SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void * userdata)
* to set the value of the userdata. We are going to use it to store the
* prompt.
*/
int
#ifdef CK_ANSIC
ssl_passwd_callback(char *buf, int len, int rwflag, VOID * userdata)
#else /* CK_ANSIC */
ssl_passwd_callback(buf,len,rwflag,userdata)
char * buf; int len; int rwflag; VOID *userdata;
#endif /* CK_ANSIC */
{
extern char pwbuf[];
extern int pwflg, pwcrypt;
int ok;
char *prompt=NULL;
if ( pwbuf[0] && pwflg ) {
int n;
n = ckstrncpy(buf,pwbuf,len);
#ifdef OS2
if ( pwcrypt )
ck_encrypt((char *)buf);
#endif /* OS2 */
return(n);
}
if ( userdata == NULL )
prompt="Enter certificate passphrase: ";
else
prompt=(char*)userdata;
ok = uq_txt(NULL,prompt,2,NULL,buf,len,NULL,DEFAULT_UQ_TIMEOUT);
return(ok > 0 ? strlen(buf) : 0);
}
/* Attempts to load certificate data into the TLS context structures */
/* Returns 1 on success; 0 on failure */
int
tls_load_certs(SSL_CTX * ctx, SSL * con, int server)
{
int rc = 1;
extern int quiet;
if ( !ck_ssleay_is_installed() )
return(0);
debug(F111,"tls_load_certs","SSL_CTX",ctx);
debug(F111,"tls_load_certs","SSL",con);
debug(F111,"tls_load_certs","server",server);
if ( con ) {
if (ssl_rsa_cert_file) {
if ( ssl_debug_flag )
printf("Loading RSA certificate into SSL\r\n");
rc = SSL_use_certificate_file(con, ssl_rsa_cert_file,
X509_FILETYPE_PEM);
if (!rc)
{
if ( !quiet || ssl_debug_flag )
printf("Error loading certificate from %s\r\n",
ssl_rsa_cert_file);
} else {
if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
rc = SSL_use_PrivateKey_file(con, ssl_rsa_key_file,
X509_FILETYPE_PEM);
if (!rc)
rc = SSL_use_PrivateKey_file(con, ssl_rsa_cert_file,
X509_FILETYPE_PEM);
if (!rc)
{
if ( !quiet || ssl_debug_flag )
printf("Error loading key from %s\r\n",
ssl_rsa_key_file);
} else {
rc = SSL_check_private_key(con);
if (!rc)
{
if ( ssl_debug_flag )
printf(
"Private key does not match the certificate public key\r\n");
}
}
}
}
if (ssl_dsa_cert_file) {
if ( ssl_debug_flag )
printf("Loading DSA certificate into SSL\r\n");
rc = SSL_use_certificate_file(con, ssl_dsa_cert_file,
X509_FILETYPE_PEM);
if (!rc)
{
if ( ssl_debug_flag ) {
printf("Error loading certificate from %s\r\n",
ssl_dsa_cert_file);
}
} else {
if (!ssl_dh_key_file || !ssl_dh_key_file[0])
makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
rc = SSL_use_PrivateKey_file(con, ssl_dh_key_file,
X509_FILETYPE_PEM);
if (!rc)
rc = SSL_use_PrivateKey_file(con, ssl_dsa_cert_file,
X509_FILETYPE_PEM);
if (!rc)
{
if ( !quiet || ssl_debug_flag ) {
printf("Error loading key from %s\r\n",
ssl_dh_key_file);
}
} else {
rc = SSL_check_private_key(con);
if (!rc)
{
if ( ssl_debug_flag )
printf(
"Private key does not match the certificate public key\n");
}
}
}
}
} else {
if (ssl_rsa_cert_file) {
if ( ssl_debug_flag )
printf("Loading RSA certificate into SSL\r\n");
rc = SSL_CTX_use_certificate_file(ctx, ssl_rsa_cert_file,
X509_FILETYPE_PEM);
if (!rc)
{
if ( !quiet || ssl_debug_flag )
printf("Error loading certificate from %s\r\n",
ssl_rsa_cert_file);
} else {
if (!ssl_rsa_key_file || !ssl_rsa_key_file[0])
makestr(&ssl_rsa_key_file,ssl_rsa_cert_file);
rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_key_file,
X509_FILETYPE_PEM);
if (!rc)
rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_cert_file,
X509_FILETYPE_PEM);
if (!rc) {
if ( ssl_debug_flag )
printf("Error loading key from %s\r\n",ssl_rsa_key_file);
} else {
rc = SSL_CTX_check_private_key(ctx);
if (!rc) {
if ( ssl_debug_flag )
printf(
"Private key does not match the certificate public key\r\n");
}
}
}
}
if (ssl_dsa_cert_file) {
if ( ssl_debug_flag )
printf("Loading DSA certificate into SSL\r\n");
rc = SSL_CTX_use_certificate_file(ctx, ssl_dsa_cert_file,
X509_FILETYPE_PEM);
if (!rc) {
if ( ssl_debug_flag ) {
printf("Error loading certificate from %s\r\n",
ssl_dsa_cert_file);
}
} else {
if (!ssl_dh_key_file || !ssl_dh_key_file[0])
makestr(&ssl_dh_key_file,ssl_dsa_cert_file);
rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dh_key_file,
X509_FILETYPE_PEM);
if (!rc)
rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dsa_cert_file,
X509_FILETYPE_PEM);
if (!rc) {
if ( ssl_debug_flag )
printf("Error loading key from %s\r\n",ssl_dh_key_file);
} else {
rc = SSL_CTX_check_private_key(ctx);
if (!rc) {
if ( ssl_debug_flag )
printf(
"Private key does not match the certificate public key\n");
}
}
}
}
}
if (ssl_rsa_cert_chain_file && server) {
int skip1st = 0;
if (ssl_debug_flag)
printf("Loading RSA Certificate Chain into SSL\r\n");
if (!ckstrcmp(ssl_rsa_cert_chain_file,ssl_rsa_cert_file,-1,
#ifdef OS2
0
#else
1
#endif /* OS2 */
))
skip1st = 1;
rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_rsa_cert_chain_file);
if (!rc && ssl_debug_flag)
printf("Error loading RSA Certificate Chain into SSL\r\n");
}
if (ssl_dsa_cert_chain_file && server) {
int skip1st = 0;
if (ssl_debug_flag)
printf("Loading DSA Certificate Chain into SSL\r\n");
if (!ckstrcmp(ssl_dsa_cert_chain_file,ssl_dsa_cert_file,-1,
#ifdef OS2
0
#else
1
#endif /* OS2 */
))
skip1st = 1;
rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_dsa_cert_chain_file);
if (!rc && ssl_debug_flag)
printf("Error loading DSA Certificate Chain into SSL\r\n");
}
return(rc);
}
VOID
#ifdef CK_ANSIC
ssl_once_init(void)
#else
ssl_once_init()
#endif /* CK_ANSIC */
{
COMP_METHOD * cm;
if ( !ck_ssleay_is_installed() )
return;
debug(F111,"Kermit built for OpenSSL",OPENSSL_VERSION_TEXT,SSLEAY_VERSION_NUMBER);
#ifndef OS2ONLY
debug(F111,"OpenSSL Library",SSLeay_version(SSLEAY_VERSION),
SSLeay());
debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_BUILT_ON),0);
debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_CFLAGS),0);
debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_PLATFORM),0);
/* The following test is suggested by Richard Levitte */
if (((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xffffff0f)
#ifdef OS2
|| ckstrcmp(OPENSSL_VERSION_TEXT,(char *)SSLeay_version(SSLEAY_VERSION),-1,1)
#endif /* OS2 */
) {
ssl_installed = 0;
debug(F111,"OpenSSL Version does not match. Built with",
SSLeay_version(SSLEAY_VERSION),SSLEAY_VERSION_NUMBER);
printf("?OpenSSL libraries do not match required version.");
printf(" SSL\\TLS support disabled\r\n\r\n");
bleep(BP_FAIL);
#ifdef SSLDLL
ck_ssl_unloaddll();
ck_crypto_unloaddll();
#endif /* SSLDLL */
return;
}
#endif /* OS2ONLY */
/* init things so we will get meaningful error messages
* rather than numbers
*/
SSL_load_error_strings();
#ifdef SSHBUILTIN
OPENSSL_add_all_algorithms_noconf();
#else
/* SSL_library_init() only loads those ciphers needs for SSL */
/* These happen to be a similar set to those required for SSH */
/* but they are not a complete set of ciphers provided by the */
/* crypto library. */
SSL_library_init();
#endif /* SSHBUILTIN */
#ifdef ZLIB
cm = COMP_zlib();
if (cm != NULL && cm->type != NID_undef) {
SSL_COMP_add_compression_method(0xe0, cm); /* EAY's ZLIB ID */
}
#endif /* ZLIB */
cm = COMP_rle();
if (cm != NULL && cm->type != NID_undef)
SSL_COMP_add_compression_method(0xe1, cm); /* EAY's RLE ID */
/* Ensure the Random number generator has enough entropy */
if ( !RAND_status() ) {
char buffer[256]="";
char randombytes[256];
int rc1 = -1, rc2 = 1; /* assume failure and success */
debug(F110,"ssl_once_init","!RAND_status()",0);
if ( ssl_rnd_file == NULL ) {
debug(F110,"ssl_rnd_file","ssl_rnd_file is NULL",0);
RAND_file_name(buffer,256);
if ( buffer[0] )
makestr(&ssl_rnd_file, buffer);
else
makestr(&ssl_rnd_file,".rnd");
}
debug(F110,"ssl_rnd_file",ssl_rnd_file,0);
rc1 = RAND_egd(ssl_rnd_file);
debug(F111,"ssl_once_init","RAND_egd()",rc1);
if ( rc1 <= 0 ) {
rc2 = RAND_load_file(ssl_rnd_file, -1);
debug(F111,"ssl_once_init","RAND_load_file()",rc1);
}
if ( rc1 <= 0 && !rc2 )
{
time_t t = time(NULL);
int tlen = sizeof(time_t);
int pid = getpid();
int plen = sizeof(int);
int n;
#ifndef RAND_MAX
#define RAND_MAX 0x7FFF
#endif
debug(F110,"ssl_once_init","calling RAND_seed()",0);
RAND_seed((unsigned char *)&t, tlen);
RAND_seed((unsigned char *)&pid, plen);
srand((unsigned int)t);
sprintf(buffer, "%.0f", (((double)(rand()%RAND_MAX)/RAND_MAX)*
(sizeof(randombytes)-128-1)));
n = (atoi(buffer)+1)%(sizeof(randombytes)-128-1);
RAND_seed(randombytes, 128);
}
if ( !RAND_status() ) {
debug(F110,"ssl_once_init","Unable to initialize PRNG",0);
printf(" Unable to load 'random state'\n");
printf(" SSL and TLS are unavailble.\n");
printf(" Use SET AUTH SSL RANDOM-FILE <file> command to provide random data.\n");
printf(" Specified file will be overwritten with new random data after use.\n");
return;
}
if ( ssl_rnd_file ) {
int rc = RAND_write_file(ssl_rnd_file);
debug(F111,"ssl_once_init","RAND_write_file()",rc);
}
}
#ifdef NT
// Initialize additional OID types for use when saving certs to a file
OBJ_create("2.99999.3","SET.ex3","SET x509v3 extension 3");
#endif /* NT */
/* make sure we have somewhere we can log errors to */
bio_err=BIO_new(BIO_s_mem());
debug(F100,"ssl_once_init() complete","",0);
}
int
#ifdef CK_ANSIC
ssl_tn_init(int mode)
#else
ssl_tn_init(mode) int mode;
#endif /* CK_ANSIC */
{
#ifdef KRB5
extern char * k5_keytab;
extern char * krb5_d_srv;
#endif /* KRB5 */
static int last_ssl_mode = -1;
SSL * ssl_conx=NULL, * tls_conx=NULL;
ssl_initialized = 0;
if ( !ck_ssleay_is_installed() )
return(0);
debug(F111,"ssl_tn_init","mode",mode);
if (ssl_debug_flag)
printf("SSL_DEBUG_FLAG on\r\n");
if (last_ssl_mode != mode) {
if (ssl_ctx) {
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
if (tls_ctx) {
SSL_CTX_free(tls_ctx);
tls_ctx = NULL;
}
}
if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
if ( mode == SSL_CLIENT ) {
ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
/* This can fail because we do not have RSA available */
if ( !ssl_ctx ) {
debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
}
if ( !ssl_ctx ) {
debug(F110,"ssl_tn_init","SSLv3_client_method failed",0);
last_ssl_mode = -1;
return(0);
}
#ifndef COMMENT
tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
#else /* COMMENT */
tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
/* This can fail because we do not have RSA available */
if ( !tls_ctx ) {
debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
}
#endif /* COMMENT */
if ( !tls_ctx ) {
debug(F110,"ssl_tn_init","TLSv1_client_method failed",0);
last_ssl_mode = -1;
return(0);
}
#ifdef USE_CERT_CB
SSL_CTX_set_client_cert_cb(ssl_ctx,ssl_client_cert_callback);
SSL_CTX_set_client_cert_cb(tls_ctx,ssl_client_cert_callback);
#endif /* USE_CERT_CB */
} else if (mode == SSL_SERVER) {
/* We are a server */
ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
/* This can fail because we do not have RSA available */
if ( !ssl_ctx ) {
debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_server_method());
}
if ( !ssl_ctx ) {
debug(F110,"ssl_tn_init","SSLv3_server_method failed",0);
last_ssl_mode = -1;
return(0);
}
#ifdef COMMENT
tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
#else /* COMMENT */
tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method());
/* This can fail because we do not have RSA available */
if ( !tls_ctx ) {
debug(F110,"ssl_tn_init","SSLv23_server_method failed",0);
tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
}
#endif /* COMMENT */
if ( !tls_ctx ) {
debug(F110,"ssl_tn_init","TLSv1_server_method failed",0);
last_ssl_mode = -1;
return(0);
}
} else /* Unknown mode */
return(0);
if ( !inserver ) {
SSL_CTX_set_default_passwd_cb(ssl_ctx,
(pem_password_cb *)ssl_passwd_callback);
SSL_CTX_set_default_passwd_cb(tls_ctx,
(pem_password_cb *)ssl_passwd_callback);
}
/* for SSL switch on all the interoperability and bug
* workarounds so that we will communicate with people
* that cannot read poorly written specs :-)
* for TLS be sure to prevent use of SSLv2
*/
SSL_CTX_set_options(ssl_ctx,SSL_OP_ALL|SSL_OP_NO_SSLv2);
SSL_CTX_set_options(tls_ctx,
SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
SSL_CTX_set_info_callback(ssl_ctx,ssl_client_info_callback);
SSL_CTX_set_info_callback(tls_ctx,ssl_client_info_callback);
#ifndef COMMENT
/* Set the proper caching mode */
if ( mode == SSL_SERVER ) {
SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_SERVER);
SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_SERVER);
} else {
SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_CLIENT);
SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_CLIENT);
}
SSL_CTX_set_session_id_context(ssl_ctx,(CHAR *)"1",1);
SSL_CTX_set_session_id_context(tls_ctx,(CHAR *)"2",1);
#else /* COMMENT */
SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_OFF);
SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_OFF);
#endif /* COMMENT */
}
/* The server uses defaults for the certificate files. */
/* The client does not. */
if (mode == SSL_SERVER) {
char cert_filepath[1024];
const char * defdir = NULL;
DH * dh = NULL;
defdir = getenv("SSL_CERT_DIR");
if ( !defdir ) {
#ifdef OS2
defdir = exedir;
#else /* OS2 */
defdir = X509_get_default_cert_dir();
#endif /* OS2 */
debug(F110,"ssl_tn_init - setting default directory to",defdir,0);
}
if ( !defdir )
defdir = "";
if (!ssl_rsa_cert_file) {
/* we need to know the fullpath to the location of the
* certificate that we will be running with as we cannot
* be sure of the cwd when we are launched
*/
sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa.pem");
if (zchki(cert_filepath) > 0)
makestr(&ssl_rsa_cert_file,cert_filepath);
}
if (ssl_rsa_cert_file && !ssl_rsa_key_file) {
/* we need to know the fullpath to the location of the
* certificate that we will be running with as we cannot
* be sure of the cwd when we are launched
*/
sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa-key.pem");
if (zchki(cert_filepath) > 0)
makestr(&ssl_rsa_key_file,cert_filepath);
}
if (!ssl_dsa_cert_file) {
/* we need to know the fullpath to the location of the
* certificate that we will be running with as we cannot
* be sure of the cwd when we are launched
*/
sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa.pem");
if (zchki(cert_filepath) > 0)
makestr(&ssl_dsa_cert_file,cert_filepath);
}
if (ssl_dsa_cert_file && !ssl_dh_key_file) {
/* we need to know the fullpath to the location of the
* certificate that we will be running with as we cannot
* be sure of the cwd when we are launched
*/
sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa-key.pem");
if (zchki(cert_filepath) > 0)
makestr(&ssl_dh_key_file,cert_filepath);
}
if (!ssl_crl_dir) {
/* we need to know the fullpath to the location of the
* certificate that we will be running with as we cannot
* be sure of the cwd when we are launched
*/
sprintf(cert_filepath,"%s/crl",defdir);
if (zchki(cert_filepath) > 0)
makestr(&ssl_crl_dir,cert_filepath);
}
if (ssl_only_flag && !tls_load_certs(ssl_ctx,ssl_con,1)) {
debug(F110,"ssl_tn_init","Unable to load SSL certs",0);
last_ssl_mode = -1;
return(0);
}
if (tls_only_flag && !tls_load_certs(tls_ctx,tls_con,1)) {
debug(F110,"ssl_tn_init","Unable to load TLS certs",0);
last_ssl_mode = -1;
return(0);
}
if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) {
/* we may require a temp 512 bit RSA key because of the
* wonderful way export things work ... if so we generate
* one now!
*/
SSL_CTX_set_tmp_rsa_callback(ssl_ctx, tmp_rsa_cb);
SSL_CTX_set_tmp_dh_callback( ssl_ctx, tmp_dh_cb);
SSL_CTX_set_tmp_rsa_callback(tls_ctx, tmp_rsa_cb);
SSL_CTX_set_tmp_dh_callback( tls_ctx, tmp_dh_cb);
dh = tmp_dh_cb(NULL,0,512);
SSL_CTX_set_tmp_dh(ssl_ctx,dh);
SSL_CTX_set_tmp_dh(tls_ctx,dh);
/* The following code is only called if we are using a
* certificate with an RSA public key and where the
* certificate has a key length less than 512 bits or is
* marked for signing only. This is so we can support
* the greatest legal privacy level with exportable clients.
*/
if (SSL_CTX_need_tmp_RSA(ssl_ctx) ||
SSL_CTX_need_tmp_RSA(tls_ctx))
{
RSA *rsa;
if ( ssl_debug_flag )
printf("Generating temp (512 bit) RSA key ...\r\n");
rsa=RSA_generate_key(512,RSA_F4,NULL,NULL);
if ( ssl_debug_flag )
printf("Generation of temp (512 bit) RSA key done\r\n");
if (SSL_CTX_need_tmp_RSA(ssl_ctx)) {
if (!SSL_CTX_set_tmp_rsa(ssl_ctx,rsa)) {
if ( ssl_debug_flag )
printf(
"Failed to assign generated temp RSA key to SSL!\r\n");
}
}
if (SSL_CTX_need_tmp_RSA(tls_ctx)) {
if (!SSL_CTX_set_tmp_rsa(tls_ctx,rsa)) {
if ( ssl_debug_flag )
printf(
"Failed to assign generated temp RSA key to TLS!\r\n");
}
}
RSA_free(rsa);
if ( ssl_debug_flag )
printf("Assigned temp (512 bit) RSA key\r\n");
}
}
}
/* make sure we will find certificates in the standard
* location ... otherwise we don't look anywhere for
* these things which is going to make client certificate
* exchange rather useless :-)
* In OS2, default values for ssl_verify_file and ssl_verify_path.
*/
#ifdef OS2
#ifdef NT
{
/* The defaults in the SSL crypto library are not appropriate for OS/2 */
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
if (isdir(path) &&
SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
debug(F110,"ssl_tn_init certificate verify dir",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification Directory: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
if (isdir(path) &&
SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
debug(F110,"ssl_tn_init certificate verify dir",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification Directory: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
if (isdir(path) &&
SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
debug(F110,"ssl_tn_init certificate verify dir",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification Directory: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
}
ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
if (zchki(path) > 0 &&
SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
debug(F110,"ssl_tn_init certificate verify file",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification File: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
}
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
if (zchki(path) > 0 &&
SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
debug(F110,"ssl_tn_init certificate verify file",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification File: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
if (zchki(path) > 0 &&
SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
debug(F110,"ssl_tn_init certificate verify file",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification File: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
}
}
#else /* NT */
{
/* The defaults in the SSL crypto library are not appropriate for OS/2 */
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
if (isdir(path) &&
SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) {
debug(F110,"ssl_tn_init certificate verify dir",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification Directory: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,NULL,path);
}
ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
if (zchki(path) > 0 &&
SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) {
debug(F110,"ssl_tn_init certificate verify file",path,0);
if (ssl_debug_flag)
printf(" Certificate Verification File: %s\r\n",path);
SSL_CTX_load_verify_locations(ssl_ctx,path,NULL);
}
}
#endif /* NT */
#else /* OS2 */
SSL_CTX_set_default_verify_paths(ssl_ctx);
SSL_CTX_set_default_verify_paths(tls_ctx);
#endif /* OS2 */
if (ssl_verify_file) {
if (zchki(ssl_verify_file) > 0 &&
SSL_CTX_load_verify_locations(tls_ctx,ssl_verify_file,NULL) == 1) {
debug(F110,"ssl_tn_init certificate verify file",ssl_verify_file,0);
if (ssl_debug_flag)
printf(" Certificate Verification File: %s\r\n",ssl_verify_file);
SSL_CTX_load_verify_locations(ssl_ctx,ssl_verify_file,NULL);
}
}
if (ssl_verify_dir && isdir(ssl_verify_dir)) {
if (SSL_CTX_load_verify_locations(tls_ctx,NULL,ssl_verify_dir) == 1) {
debug(F110,"ssl_tn_init certificate verify dir",ssl_verify_dir,0);
if (ssl_debug_flag)
printf(" Certificate Verification Directory: %s\r\n",ssl_verify_dir);
SSL_CTX_load_verify_locations(ssl_ctx,NULL,ssl_verify_dir);
}
}
if (mode == SSL_SERVER) {
SSL_CTX_set_verify(ssl_ctx,
ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
ssl_server_verify_callback);
SSL_CTX_set_verify(tls_ctx,
ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0,
ssl_server_verify_callback);
} else {
SSL_CTX_set_verify(ssl_ctx,ssl_verify_flag,
ssl_client_verify_callback);
SSL_CTX_set_verify(tls_ctx,ssl_verify_flag,
ssl_client_verify_callback);
}
/* Free the existing CRL Store */
if (crl_store) {
X509_STORE_free(crl_store);
crl_store = NULL;
}
/* set up the new CRL Store */
crl_store = X509_STORE_new();
if (crl_store) {
#ifdef OS2
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
if (isdir(path) &&
X509_STORE_load_locations(crl_store,NULL,path) == 1) {
debug(F110,"ssl_tn_init crl dir",path,0);
if (ssl_debug_flag)
printf(" CRL Directory: %s\r\n",path);
}
#ifdef NT
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
if (isdir(path) &&
X509_STORE_load_locations(crl_store,NULL,path) == 1) {
debug(F110,"ssl_tn_init crl dir",path,0);
if (ssl_debug_flag)
printf(" CRL Directory: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
if (isdir(path) &&
X509_STORE_load_locations(crl_store,NULL,path) == 1) {
debug(F110,"ssl_tn_init crl dir",path,0);
if (ssl_debug_flag)
printf(" CRL Directory: %s\r\n",path);
}
#endif /* NT */
ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
if (zchki(path) > 0 &&
X509_STORE_load_locations(crl_store,path,NULL) == 1) {
debug(F110,"ssl_tn_init crl file",path,0);
if (ssl_debug_flag)
printf(" CRL File: %s\r\n",path);
}
#ifdef NT
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
if (zchki(path) > 0 &&
X509_STORE_load_locations(crl_store,path,NULL) == 1) {
debug(F110,"ssl_tn_init crl file",path,0);
if (ssl_debug_flag)
printf(" CRL File: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
if (zchki(path) > 0 &&
X509_STORE_load_locations(crl_store,path,NULL) == 1) {
debug(F110,"ssl_tn_init crl file",path,0);
if (ssl_debug_flag)
printf(" CRL File: %s\r\n",path);
}
#endif /* NT */
#endif /* OS2 */
if (ssl_crl_file || ssl_crl_dir) {
if (ssl_crl_file && zchki(ssl_crl_file) > 0 &&
X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 1) {
debug(F110,"ssl_tn_init crl file",ssl_crl_file,0);
if (ssl_debug_flag)
printf(" CRL File: %s\r\n",ssl_crl_file);
}
if (ssl_crl_dir && isdir(ssl_crl_dir) &&
X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 1) {
debug(F110,"ssl_tn_init crl dir",ssl_crl_dir,0);
if (ssl_debug_flag)
printf(" CRL Directory: %s\r\n",ssl_crl_dir);
}
}
#ifndef OS2
else {
X509_STORE_set_default_paths(crl_store);
}
#endif /* OS2 */
}
#ifndef COMMENT
ssl_conx = ssl_con;
ssl_con=(SSL *)SSL_new(ssl_ctx);
if ( !ssl_con ) {
debug(F110,"ssl_tn_init","SSL_new(ssl_con) failed",0);
last_ssl_mode = -1;
ssl_con = ssl_conx;
return(0);
}
if (ssl_conx) {
if ( mode == SSL_CLIENT ) {
SSL_set_session(ssl_con, SSL_get_session(ssl_conx));
}
#ifdef SSL_KRB5
if (ssl_conx->kssl_ctx) {
kssl_ctx_free(ssl_conx->kssl_ctx);
ssl_conx->kssl_ctx = NULL;
}
#endif /* SSL_KRB5 */
SSL_free(ssl_conx);
ssl_conx = NULL;
}
tls_conx = tls_con;
tls_con=(SSL *)SSL_new(tls_ctx);
if ( !tls_con ) {
debug(F110,"ssl_tn_init","SSL_new(tls_con) failed",0);
last_ssl_mode = -1;
tls_con = tls_conx;
return(0);
}
if (tls_conx) {
if ( mode == SSL_CLIENT )
SSL_set_session(tls_con, SSL_get_session(tls_conx));
#ifdef SSL_KRB5
if (tls_conx->kssl_ctx) {
kssl_ctx_free(tls_conx->kssl_ctx);
tls_conx->kssl_ctx = NULL;
}
#endif /* SSL_KRB5 */
SSL_free(tls_conx);
tls_conx = NULL;
}
#else /* COMMENT */
/* I don't know why this does not work to reuse the connection. */
if ( ssl_con ) {
SSL_clear(ssl_con);
SSL_set_session(ssl_con,NULL);
SSL_set_accept_state(ssl_con) ;
} else {
ssl_con=(SSL *)SSL_new(ssl_ctx);
if (!ssl_con) {
debug(F110,"ssl_tn_init","SSL_new(ssl_ctx) failed",0);
last_ssl_mode = -1;
ssl_con = ssl_conx;
return(0);
}
}
if ( tls_con ) {
SSL_clear(tls_con);
SSL_set_session(tls_con,NULL);
SSL_set_accept_state(tls_con) ;
} else {
tls_con=(SSL *)SSL_new(tls_ctx);
if ( !tls_con ) {
debug(F110,"ssl_tn_init","SSL_new(tls_ctx) failed",0);
last_ssl_mode = -1;
tls_con = tls_conx;
return(0);
}
}
#endif /* COMMENT */
#ifdef SSL_KRB5
#ifndef KRB5_SERVICE_NAME
#define KRB5_SERVICE_NAME "host"
#endif
if (ssl_con->kssl_ctx == NULL)
ssl_con->kssl_ctx = kssl_ctx_new();
if (tls_con->kssl_ctx == NULL)
tls_con->kssl_ctx = kssl_ctx_new();
if (mode == SSL_SERVER) {
if (ssl_con->kssl_ctx != NULL)
kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
if (tls_con->kssl_ctx != NULL)
kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_KEYTAB, k5_keytab);
} else {
if (ssl_con->kssl_ctx != NULL)
kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVER, szHostName);
if (tls_con->kssl_ctx != NULL)
kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVER, szHostName);
}
kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVICE,
krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVICE,
krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
#endif /* SSL_KRB5 */
if (ssl_cipher_list) {
SSL_set_cipher_list(ssl_con,ssl_cipher_list);
SSL_set_cipher_list(tls_con,ssl_cipher_list);
} else {
char * p;
if (p = getenv("SSL_CIPHER")) {
SSL_set_cipher_list(ssl_con,p);
SSL_set_cipher_list(tls_con,p);
} else {
SSL_set_cipher_list(ssl_con,DEFAULT_CIPHER_LIST);
SSL_set_cipher_list(tls_con,DEFAULT_CIPHER_LIST);
}
}
ssl_verify_depth = -1;
if ( ssl_debug_flag )
printf("SSL/TLS init done!\r\n");
ssl_initialized = 1;
last_ssl_mode = mode;
debug(F110,"ssl_tn_init","done",0);
return(1);
}
#ifndef NOHTTP
int
#ifdef CK_ANSIC
ssl_http_init(char * hostname)
#else
ssl_http_init(hostname) char * hostname;
#endif /* CK_ANSIC */
{
#ifdef KRB5
extern char * k5_keytab;
extern char * krb5_d_srv;
#endif /* KRB5 */
SSL * tls_conx=NULL;
ssl_http_initialized = 0;
if ( !ck_ssleay_is_installed() )
return(0);
debug(F110,"ssl_http_init",hostname,0);
if (ssl_debug_flag)
printf("SSL_DEBUG_FLAG on\r\n");
if (!tls_http_ctx ) {
#ifdef COMMENT
/* too many web servers still do not support TLSv1 */
tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
#else /* COMMENT */
tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
/* This can fail because we do not have RSA available */
if ( !tls_http_ctx ) {
debug(F110,"ssl_http_init","SSLv23_client_method failed",0);
tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
}
#endif /* COMMENT */
if ( !tls_http_ctx ) {
debug(F110,"ssl_http_init","TLSv1_client_method failed",0);
return(0);
}
#ifdef USE_CERT_CB
SSL_CTX_set_client_cert_cb(tls_http_ctx,ssl_client_cert_callback);
#endif /* USE_CERT_CB */
}
SSL_CTX_set_default_passwd_cb(tls_http_ctx,
(pem_password_cb *)ssl_passwd_callback);
/* for SSL switch on all the interoperability and bug
* workarounds so that we will communicate with people
* that cannot read poorly written specs :-)
* for TLS be sure to prevent use of SSLv2
*/
SSL_CTX_set_options(tls_http_ctx,
SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA);
SSL_CTX_set_info_callback(tls_http_ctx,ssl_client_info_callback);
#ifndef COMMENT
SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_CLIENT);
SSL_CTX_set_session_id_context(tls_http_ctx,(CHAR *)"3",1);
#else /* COMMENT */
SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_OFF);
#endif /* COMMENT */
/* make sure we will find certificates in the standard
* location ... otherwise we don't look anywhere for
* these things which is going to make client certificate
* exchange rather useless :-)
*/
#ifdef OS2
#ifdef NT
{
/* The defaults in the SSL crypto library are not appropriate for OS/2 */
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-dir: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-dir: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-dir: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-file: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-file: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-file: %s\r\n",path);
}
}
#else /* NT */
{
/* The defaults in the SSL crypto library are not appropriate for OS/2 */
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-dir: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load path",path,0);
if (ssl_debug_flag)
printf("?Unable to load verify-file: %s\r\n",path);
}
}
#endif /* NT */
#else /* OS2 */
SSL_CTX_set_default_verify_paths(tls_http_ctx);
#endif /* OS2 */
if (ssl_verify_file &&
SSL_CTX_load_verify_locations(tls_http_ctx,ssl_verify_file,NULL) == 0) {
debug(F110,"ssl_http_init unable to load ssl_verify_file",ssl_verify_file,0);
if (ssl_debug_flag)
printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
}
if (ssl_verify_dir &&
SSL_CTX_load_verify_locations(tls_http_ctx,NULL,ssl_verify_dir) == 0) {
debug(F110,"ssl_http_init unable to load ssl_verify_dir",ssl_verify_dir,0);
if (ssl_debug_flag)
printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
}
SSL_CTX_set_verify(tls_http_ctx,ssl_verify_flag,
ssl_client_verify_callback);
/* Free the existing CRL Store */
if (crl_store) {
X509_STORE_free(crl_store);
crl_store = NULL;
}
/* set up the new CRL Store */
crl_store = X509_STORE_new();
if (crl_store) {
#ifdef OS2
char path[CKMAXPATH];
ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load dir",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-dir: %s\r\n",path);
}
#ifdef NT
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL);
if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load dir",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-dir: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL);
if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
debug(F110,"ssl_http_init unable to load dir",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-dir: %s\r\n",path);
}
#endif /* NT */
ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load file",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-file: %s\r\n",path);
}
#ifdef NT
ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL);
if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load file",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-file: %s\r\n",path);
}
ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL);
if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
debug(F110,"ssl_http_init unable to load file",path,0);
if (ssl_debug_flag)
printf("?Unable to load crl-file: %s\r\n",path);
}
#endif /* NT */
#endif /* OS2 */
if (ssl_crl_file || ssl_crl_dir) {
if (ssl_crl_file &&
X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
debug(F110,"ssl_http_init unable to load ssl_crl_file",ssl_crl_file,0);
if (ssl_debug_flag)
printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
}
if (ssl_crl_dir &&
X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
debug(F110,"ssl_http_init unable to load ssl_crl_dir",ssl_crl_dir,0);
if (ssl_debug_flag)
printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
}
} else {
X509_STORE_set_default_paths(crl_store);
}
}
#ifndef COMMENT
tls_conx = tls_http_con;
tls_http_con=(SSL *)SSL_new(tls_http_ctx);
if ( !tls_http_con ) {
debug(F110,"ssl_http_init","SSL_new(tls_http_con) failed",0);
tls_http_con = tls_conx;
return(0);
}
if (tls_conx) {
SSL_set_session(tls_http_con, SSL_get_session(tls_conx));
#ifdef SSL_KRB5
if (tls_conx->kssl_ctx) {
kssl_ctx_free(tls_conx->kssl_ctx);
tls_conx->kssl_ctx = NULL;
}
#endif /* SSL_KRB5 */
SSL_free(tls_conx);
tls_conx = NULL;
}
#else /* COMMENT */
/* I don't know why this does not work to reuse the connection. */
if ( tls_http_con ) {
SSL_clear(tls_http_con);
SSL_set_session(tls_http_con,NULL);
SSL_set_accept_state(tls_http_con) ;
} else {
tls_http_con=(SSL *)SSL_new(tls_http_ctx);
if ( !tls_http_con ) {
debug(F110,"ssl_http_init","SSL_new(tls_http_ctx) failed",0);
tls_http_con = tls_conx;
return(0);
}
}
#endif /* COMMENT */
#ifdef SSL_KRB5
#ifndef KRB5_SERVICE_NAME
#define KRB5_SERVICE_NAME "host"
#endif
if (tls_http_con->kssl_ctx == NULL)
tls_http_con->kssl_ctx = kssl_ctx_new();
if (tls_http_con->kssl_ctx != NULL)
kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVER, hostname);
kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVICE,
krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME);
#endif /* SSL_KRB5 */
if (ssl_cipher_list)
SSL_set_cipher_list(tls_http_con,ssl_cipher_list);
else {
char * p;
if (p = getenv("SSL_CIPHER")) {
SSL_set_cipher_list(tls_http_con,p);
} else {
SSL_set_cipher_list(tls_http_con,DEFAULT_CIPHER_LIST);
}
}
ssl_verify_depth = -1;
if ( ssl_debug_flag )
printf("SSL/TLS init done!\r\n");
ssl_http_initialized = 1;
return(1);
}
#endif /* NOHTTP */
char *
ssl_get_dNSName(ssl) SSL * ssl;
{
static char *dns = NULL;
X509 *server_cert = NULL;
int i;
X509_EXTENSION *ext = NULL;
STACK_OF(GENERAL_NAME) *ialt = NULL;
GENERAL_NAME *gen = NULL;
if ( dns ) {
free(dns);
dns = NULL;
}
if (server_cert = SSL_get_peer_certificate(ssl)) {
if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1))<0)
return NULL;
if (!(ext = X509_get_ext(server_cert, i)))
return NULL;
X509V3_add_standard_extensions();
if (!(ialt = X509V3_EXT_d2i(ext)))
return NULL;
for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
gen = sk_GENERAL_NAME_value(ialt, i);
if (gen->type == GEN_DNS) {
if(!gen->d.ia5 || !gen->d.ia5->length)
break;
dns = malloc(gen->d.ia5->length + 1);
if (dns) {
memcpy(dns, gen->d.ia5->data, gen->d.ia5->length);
dns[gen->d.ia5->length] = 0;
}
break;
}
}
X509V3_EXT_cleanup();
}
cleanup:
if (ialt) sk_GENERAL_NAME_free(ialt);
if (server_cert) X509_free(server_cert);
return dns;
}
char *
ssl_get_commonName(ssl) SSL * ssl;
{
static char name[256];
int err;
X509 *server_cert;
if (server_cert = SSL_get_peer_certificate(ssl)) {
err = X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
NID_commonName, name, sizeof(name));
X509_free(server_cert);
}
if (err > 0)
return name;
else
return NULL;
}
char *
ssl_get_issuer_name(ssl) SSL * ssl;
{
static char name[256];
X509 *server_cert;
name[0] = '\0';
if (server_cert = SSL_get_peer_certificate(ssl)) {
X509_NAME_oneline(X509_get_issuer_name(server_cert),name,sizeof(name));
X509_free(server_cert);
return name;
}
else {
#ifdef COMMENT
fprintf(stderr, "Warning: No certificate from server!\r\n");
#endif /* COMMENT */
return NULL;
}
}
char *
ssl_get_subject_name(ssl) SSL * ssl;
{
static char name[256];
X509 *server_cert;
name[0] = '\0';
if (server_cert = SSL_get_peer_certificate(ssl)) {
X509_NAME_oneline(X509_get_subject_name(server_cert),name,sizeof(name));
X509_free(server_cert);
return name;
}
else
return NULL;
}
#ifdef COMMENT
#ifdef CK_SSL
&& !(ck_ssleay_is_installed() &&
(tls_active_flag || ssl_active_flag) &&
ssl_anonymous_cipher(tls_active_flag?tls_con:ssl_con))
#endif /* CK_SSL */
int
ssl_anonymous_cipher(ssl) SSL * ssl;
{
X509 * cert;
if (sstelnet)
cert = SSL_get_certificate(ssl);
else
cert = SSL_get_peer_certificate(ssl);
if ( cert ) {
X509_free(cert);
return 0;
}
return 1;
}
#endif /* COMMENT */
/*
This one is (very much!) based on work by
Ralf S. Engelschall <rse@engelschall.com>.
Comments by Ralf.
*/
int
ssl_verify_crl(int ok, X509_STORE_CTX *ctx)
{
X509_OBJECT obj;
X509_NAME *subject = NULL;
X509_NAME *issuer = NULL;
X509 *xs = NULL;
X509_CRL *crl = NULL;
X509_REVOKED *revoked = NULL;
X509_STORE_CTX * store_ctx = NULL;
long serial;
BIO *bio = NULL;
int i, n, rc;
char *cp;
char *cp2;
/*
* Unless a revocation store for CRLs was created we
* cannot do any CRL-based verification, of course.
*/
if (!crl_store)
return ok;
store_ctx = X509_STORE_CTX_new();
if ( !store_ctx )
return(ok);
/*
* Determine certificate ingredients in advance
*/
xs = X509_STORE_CTX_get_current_cert(ctx);
subject = X509_get_subject_name(xs);
issuer = X509_get_issuer_name(xs);
/*
* OpenSSL provides the general mechanism to deal with CRLs but does not
* use them automatically when verifying certificates, so we do it
* explicitly here. We will check the CRL for the currently checked
* certificate, if there is such a CRL in the store.
*
* We come through this procedure for each certificate in the certificate
* chain, starting with the root-CA's certificate. At each step we've to
* both verify the signature on the CRL (to make sure it's a valid CRL)
* and it's revocation list (to make sure the current certificate isn't
* revoked). But because to check the signature on the CRL we need the
* public key of the issuing CA certificate (which was already processed
* one round before), we've a little problem. But we can both solve it and
* at the same time optimize the processing by using the following
* verification scheme (idea and code snippets borrowed from the GLOBUS
* project):
*
* 1. We'll check the signature of a CRL in each step when we find a CRL
* through the _subject_ name of the current certificate. This CRL
* itself will be needed the first time in the next round, of course.
* But we do the signature processing one round before this where the
* public key of the CA is available.
*
* 2. We'll check the revocation list of a CRL in each step when
* we find a CRL through the _issuer_ name of the current certificate.
* This CRLs signature was then already verified one round before.
*
* This verification scheme allows a CA to revoke its own certificate as
* well, of course.
*/
/*
* Try to retrieve a CRL corresponding to the _subject_ of
* the current certificate in order to verify it's integrity.
*/
memset((char *)&obj, 0, sizeof(obj));
X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, &obj);
X509_STORE_CTX_cleanup(store_ctx);
crl = obj.data.crl;
if (rc > 0 && crl != NULL) {
/*
* Verify the signature on this CRL
*/
if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) {
fprintf(stderr, "Invalid signature on CRL!\n");
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
X509_OBJECT_free_contents(&obj);
X509_STORE_CTX_free(store_ctx);
return 0;
}
/*
* Check date of CRL to make sure it's not expired
*/
i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
if (i == 0) {
fprintf(stderr, "Found CRL has invalid nextUpdate field.\n");
X509_STORE_CTX_set_error(ctx,
X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
X509_OBJECT_free_contents(&obj);
X509_STORE_CTX_free(store_ctx);
return 0;
}
if (i < 0) {
fprintf(stderr,
"Found CRL is expired - revoking all certificates until you get updated CRL.\n"
);
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
X509_OBJECT_free_contents(&obj);
X509_STORE_CTX_free(store_ctx);
return 0;
}
X509_OBJECT_free_contents(&obj);
}
/*
* Try to retrieve a CRL corresponding to the _issuer_ of
* the current certificate in order to check for revocation.
*/