added GNU TLS cert chain verification

git-svn-id: http://svn.berlios.de/svnroot/repos/sipsak/trunk@417 75b5f7c7-cfd4-0310-b54c-e118b2c5249a
(cherry picked from commit 450c78f42af1d5535c8ea033282d500cb7be049e)
(cherry picked from commit 7af14d989b)
mr3.8.5
nils-ohlmeier 19 years ago committed by Victor Seva
parent 2a62957108
commit eb41b0ed12

@ -17,6 +17,8 @@
* GNU General Public License for more details.
*/
#include "sipsak.h"
#if HAVE_CONFIG_H
# include "config.h"
#endif
@ -34,6 +36,22 @@ enum exit_modes exit_mode = EM_DEFAULT;
void exit_code(int code)
{
#ifdef WITH_TLS_TRANSP
if (transport == SIP_TLS_TRANSPORT) {
# ifdef USE_GNUTLS
if (tls_session) {
gnutls_deinit(tls_session);
}
if (xcred) {
gnutls_certificate_free_credentials(xcred);
}
gnutls_global_deinit();
# else /* USE_GNUTLS */
# ifdef USE_OPENSSL
# endif /* USE_OPENSSL */
# endif /* USE_GNUTLS */
}
#endif /* WITH_TLS_TRANSP */
switch(exit_mode) {
case EM_DEFAULT:

@ -91,6 +91,7 @@ void print_version() {
);
}
#ifdef HAVE_GETOPT_LONG
void print_long_help() {
print_version();
printf(
@ -158,6 +159,7 @@ void print_long_help() {
);
exit_code(0);
}
#endif
/* prints out some usage help and exits */
void print_help() {
@ -289,6 +291,9 @@ int main(int argc, char *argv[])
{"transport", 1, 0, 'E'},
{"headers", 1, 0, 'j'},
{"authhash", 1, 0, 'J'},
#ifdef WITH_TLS_TRANSP
{"tls-ca-cert", 1, 0, 'k'},
#endif
{0, 0, 0, 0}
};
#endif
@ -315,10 +320,15 @@ int main(int argc, char *argv[])
memset(buff, 0, BUFSIZE);
memset(fqdn, 0, FQDN_SIZE);
#ifdef WITH_TLS_TRANSP
cert_file = ca_file = NULL;
# ifdef USE_GNUTLS
tls_session = NULL;
xcred = NULL;
# else
# ifdef USE_OPENSSL
ctx = NULL;
ssl = NULL;
cert_file = ca_file = NULL;
# endif
#endif
#endif /* WITH_TLS_TRANSP */
@ -500,6 +510,15 @@ int main(int argc, char *argv[])
}
authhash=optarg;
break;
case 'k':
pf = fopen(optarg, "rb");
if (!pf){
fprintf(stderr, "error: unable to open the CA cert file '%s'.\n", optarg);
exit_code(2);
}
fclose(pf);
ca_file=optarg;
break;
case 'l':
lport=str_to_int(optarg);
break;
@ -935,8 +954,10 @@ int main(int argc, char *argv[])
gnutls_global_init();
//gnutls_anon_allocate_client_credentials(&anoncred);
gnutls_certificate_allocate_credentials(&xcred);
if (ca_file != NULL) {
// set the trusted CA file
gnutls_certificate_set_x509_trust_file(xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
gnutls_certificate_set_x509_trust_file(xcred, ca_file, GNUTLS_X509_FMT_PEM);
}
# else
# ifdef USE_OPENSSL
SSL_library_init();

@ -300,8 +300,10 @@
// FIXME: this has to replaced with a real evaluation
// #define WITH_TLS_TRANSP 1
// #define DEBUG 1
#ifdef WITH_TLS_TRANSP
char *cert_file, *ca_file;
# ifdef USE_GNUTLS
gnutls_session_t tls_session;
//gnutls_anon_client_credentials_t anoncred;
@ -310,7 +312,6 @@ gnutls_certificate_credentials_t xcred;
# ifdef USE_OPENSSL
SSL_CTX* ctx;
SSL* ssl;
char *cert_file, *ca_file;
# endif
# endif
#endif

@ -123,6 +123,231 @@ void check_alert(gnutls_session_t session, int ret) {
}
}
/* all the available CRLs */
gnutls_x509_crl_t *crl_list;
int crl_list_size;
/* all the available trusted CAs */
gnutls_x509_crt_t *ca_list;
int ca_list_size;
/* verifies a certificate against an other certificate which is supposed to
* be it's issuer. Also checks the crl_list of the certificate is revoked.
*/
static void verify_cert2(gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer,
gnutls_x509_crl_t *crl_list, int crl_list_size) {
unsigned int output;
time_t now = time(0);
size_t name_size;
char name[64];
/* print information about the certificates to be checked */
name_size = sizeof(name);
gnutls_x509_crt_get_dn(crt, name, &name_size);
printf("Certificate: %s\n", name);
name_size = sizeof(name);
gnutls_x509_crt_get_issuer_dn(crt, name, &name_size);
printf("Issued by: %s\n", name);
/* Get the DN of the issuer cert. */
name_size = sizeof(name);
gnutls_x509_crt_get_dn(issuer, name, &name_size);
printf("Checking against: %s\n", name);
/* Do the actual verification */
gnutls_x509_crt_verify(crt, &issuer, 1, 0, &output);
if (output & GNUTLS_CERT_INVALID) {
printf("Certificate not trusted!!!");
if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) {
printf(": no issuer was found\n");
}
if (output & GNUTLS_CERT_SIGNER_NOT_CA) {
printf(": issuer is not a CA\n");
}
}
else {
printf("Certificate trusted'n");
}
/* Now check the expiration dates */
if (gnutls_x509_crt_get_activation_time(crt) > now) {
printf("Certificate not yet activated!\n");
}
if (gnutls_x509_crt_get_expiration_time(crt) < now) {
printf("Certificate expired!\n");
}
/* Check if the certificate is revoked */
if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) {
printf("Certificate is revoked!\n");
}
}
/* Verifies a certificate against our trusted CA list. Also checks the crl_list
* if the certificate is revoked
*/
static void verify_last_cert(gnutls_x509_crt_t crt, gnutls_x509_crt_t *ca_list,
int ca_list_size, gnutls_x509_crl_t *crl_list, int crl_list_size) {
unsigned int output;
time_t now = time(0);
size_t name_size;
char name[64];
/* Print information about the certificates to be checked */
name_size = sizeof(name);
gnutls_x509_crt_get_dn(crt, name, &name_size);
printf("Certificate: %s\n", name);
name_size = sizeof(name);
gnutls_x509_crt_get_issuer_dn(crt, name, &name_size);
printf("Issued by: %s\n", name);
/* Do the actual verification */
gnutls_x509_crt_verify(crt, ca_list, ca_list_size,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output);
if (output & GNUTLS_CERT_INVALID) {
printf("Certificate not truested!\n");
if (output & GNUTLS_CERT_SIGNER_NOT_CA) {
printf(": Issuer is not a CA\n");
}
}
else {
printf("Certificate trusted\n");
}
/* Now check the expiration dates */
if (gnutls_x509_crt_get_activation_time(crt) > now) {
printf("Certificate now yet activated!\n");
}
if (gnutls_x509_crt_get_expiration_time(crt) < now) {
printf("Certificate expired!\n");
}
/* Check of the vertificate is revoked */
if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) {
printf("Certificate is revoked!\n");
}
}
/* this function will try yo verify the peer's certificate chain, ans
* also check if the hostname matches, and the activation and expiration dates.
*/
void verify_certificate_chain(gnutls_session_t session, const char *hostname,
const gnutls_datum_t *cert_chain, int cert_chain_length) {
int i;
gnutls_x509_crt_t *cert;
cert = malloc(sizeof(*cert) * cert_chain_length);
if (!cert) {
printf("gnutla: failed to allocate memory for cert chain verification'n");
return;
}
/* import all the certificates in the chain to native certificate format */
for (i = 0; i < cert_chain_length; i++) {
gnutls_x509_crt_init(&cert[i]);
gnutls_x509_crt_import(cert[i], &cert_chain[i], GNUTLS_X509_FMT_DER);
}
/* if the last certificate in the chain is seld signed ignore it.
* that is because we want to check against our trusted certificate list
*/
if (gnutls_x509_crt_check_issuer(cert[cert_chain_length - 1],
cert[cert_chain_length -1]) > 0 && cert_chain_length > 0) {
cert_chain_length--;
}
/* now verify the certificates against ther issuers in the chain */
for (i = 1; i < cert_chain_length; i++) {
verify_cert2(cert[i - 1], cert[i], crl_list, crl_list_size);
}
/* here we must verify the last certificate in the chain against our
* trusted CA list
*/
verify_last_cert(cert[cert_chain_length - 1], ca_list, ca_list_size,
crl_list, crl_list_size);
/* check if the name in the first certificate matches our destination */
if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) {
printf("The certificate's owner does not match hostname '%s'\n",
hostname);
}
for (i = 0; i < cert_chain_length; i++) {
gnutls_x509_crt_deinit(cert[i]);
}
return;
}
void verify_certificate_simple(gnutls_session_t session, const char *hostname) {
unsigned int status, cert_list_size;
const gnutls_datum_t *cert_list;
int ret;
gnutls_x509_crt_t cert;
// this verification function usese the trusted CAs in the credentials
// stucture. so you must have installed on or more CA certificates.
ret = gnutls_certificate_verify_peers2(session, &status);
if (ret < 0) {
printf("gnutls verify peer failed\n");
return;
}
if (status & GNUTLS_CERT_INVALID) {
printf("The certificate is not trusted\n");
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
printf("The certificate hasn't got a known issuer.\n");
}
if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
printf("The certificate issuer is not a CA\n");
}
}
if (status & GNUTLS_CERT_REVOKED) {
printf("The certificate has beend revoked.\n");
}
// from here on it works only with X509 certs
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509){
return;
}
if (gnutls_x509_crt_init(&cert) < 0) {
printf("gnutls crt init failed\n");
return;
}
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
if (cert_list == NULL) {
printf("gnutls did not found a certificate'n");
return;
}
// this not a real world check as only the first cert is checked!
if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)) {
printf("gnutls failed to parse certificate\n");
return;
}
// beware here we do not check for errors
if (gnutls_x509_crt_get_expiration_time(cert) < time(0)) {
printf("The certificate hax expired\n");
return;
}
if (gnutls_x509_crt_get_activation_time(cert) > time(0)) {
printf("The certificate is not yet activated\n");
return;
}
if (!gnutls_x509_crt_check_hostname(cert, hostname)) {
printf("The certificate's owner does not match hostname '%s'",
hostname);
return;
}
gnutls_x509_crt_deinit(cert);
return;
}
static const char *bin2hex(const void *bin, size_t bin_size) {
static char printable[110];
const unsigned char *_bin = bin;
@ -149,7 +374,7 @@ void print_x509_certificate_info(gnutls_session_t session) {
unsigned int algo, bits;
time_t expiration_time, activation_time;
const gnutls_datum_t *cert_list;
int cert_list_size = 0;
unsigned int cert_list_size = 0;
gnutls_x509_crt_t cert;
// check if we got a X.509 cert
@ -920,6 +1145,8 @@ int set_target(struct sockaddr_in *adr, unsigned long target, int port, int sock
#ifdef DEBUG
gnutls_session_info(tls_session);
#endif
verify_certificate_simple(tls_session, domainname);
//verify_certificate_chain(tls_session, domainname, cert_chain, cert_chain_length);
}
#endif
# else /* USE_GNUTLS */

Loading…
Cancel
Save