diff -ruN openssh-3.9p1+x509-5.1/auth2-pubkey.c openssh-3.9p1+x509-5.2/auth2-pubkey.c --- openssh-3.9p1+x509-5.1/auth2-pubkey.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/auth2-pubkey.c 2005-06-12 09:06:01.000000000 +0300 @@ -1,6 +1,6 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/config.h.in openssh-3.9p1+x509-5.2/config.h.in --- openssh-3.9p1+x509-5.1/config.h.in 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/config.h.in 2005-06-12 09:06:01.000000000 +0300 @@ -1047,6 +1047,9 @@ /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID +/* Define to 1 if `param' is member of `X509_STORE_CTX'. */ +#undef HAVE_X509_STORE_CTX_PARAM + /* Define to 1 if you have the `_getlong' function. */ #undef HAVE__GETLONG diff -ruN openssh-3.9p1+x509-5.1/configure openssh-3.9p1+x509-5.2/configure --- openssh-3.9p1+x509-5.1/configure 2004-11-19 09:06:02.000000000 +0200 +++ openssh-3.9p1+x509-5.2/configure 2005-06-12 09:06:02.000000000 +0300 @@ -24136,6 +24136,119 @@ fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi + # Check for the existence of "X509_VERIFY_PARAM *param" + echo "$as_me:$LINENO: checking for X509_STORE_CTX.param" >&5 +echo $ECHO_N "checking for X509_STORE_CTX.param... $ECHO_C" >&6 +if test "${ac_cv_member_X509_STORE_CTX_param+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static X509_STORE_CTX ac_aggr; +if (ac_aggr.param) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_X509_STORE_CTX_param=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static X509_STORE_CTX ac_aggr; +if (sizeof ac_aggr.param) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_X509_STORE_CTX_param=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_X509_STORE_CTX_param=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_X509_STORE_CTX_param" >&5 +echo "${ECHO_T}$ac_cv_member_X509_STORE_CTX_param" >&6 +if test $ac_cv_member_X509_STORE_CTX_param = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_X509_STORE_CTX_PARAM 1 +_ACEOF + + +fi + fi if test "x$ssh_x509dn_email" = "xno"; then diff -ruN openssh-3.9p1+x509-5.1/configure.ac openssh-3.9p1+x509-5.2/configure.ac --- openssh-3.9p1+x509-5.1/configure.ac 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/configure.ac 2005-06-12 09:06:00.000000000 +0300 @@ -2755,6 +2755,8 @@ ssh_x509dn_email="no" ] ) + # Check for the existence of "X509_VERIFY_PARAM *param" + AC_CHECK_MEMBERS([X509_STORE_CTX.param],,,[#include ]) fi if test "x$ssh_x509dn_email" = "xno"; then AC_DEFINE_UNQUOTED( diff -ruN openssh-3.9p1+x509-5.1/dns.c openssh-3.9p1+x509-5.2/dns.c --- openssh-3.9p1+x509-5.1/dns.c 2004-06-22 05:56:02.000000000 +0300 +++ openssh-3.9p1+x509-5.2/dns.c 2005-06-12 09:06:01.000000000 +0300 @@ -1,9 +1,12 @@ -/* $OpenBSD: dns.c,v 1.10 2004/06/21 17:36:31 avsm Exp $ */ +/* $OpenBSD$ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. * Copyright (c) 2003 Jakob Schlyter. All rights reserved. * + * X.509 certificates support: + * Copyright (c) 2005 Roumen Petrov. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,12 +41,27 @@ #include "xmalloc.h" #include "key.h" +#include "ssh-x509.h" #include "dns.h" #include "log.h" #include "uuencode.h" extern char *__progname; -RCSID("$OpenBSD: dns.c,v 1.10 2004/06/21 17:36:31 avsm Exp $"); +RCSID("$OpenBSD$"); + + +struct ssh_dns_cert_param_s { + int cert_type; + int key_tag; + int algo; + u_char *cert_data; + size_t cert_len; + u_char *b64_data; + size_t b64_len; +}; + +typedef struct ssh_dns_cert_param_s ssh_dns_cert_param; + #ifndef LWRES static const char *errset_text[] = { @@ -112,6 +130,158 @@ return success; } +static void +cert_param_clean(ssh_dns_cert_param *param) { + if (param == NULL) return; + + if (param->cert_data) { + param->cert_len = 0; + xfree(param->cert_data); + param->cert_data = NULL; + } + if (param->b64_data) { + param->b64_len = 0; + xfree(param->b64_data); + param->b64_data = NULL; + } +} + +static const char* +bind_cert_type(const ssh_dns_cert_param *param) { + switch(param->cert_type) { + case DNS_CERT_TYPE_PKIX: return("PKIX"); +#if 0 + case DNS_CERT_TYPE_SPKI: return("SPKI"); + case DNS_CERT_TYPE_PGP : return("PGP"); + case DNS_CERT_TYPE_URI : return("URI"); + case DNS_CERT_TYPE_OID : return("OID"); +#endif + default: + break; + } + return(""); +} + +static const char* +bind_key_algo(const ssh_dns_cert_param *param) { + switch(param->algo) { +#if 0 + case DNS_KEY_ALGO_UNKNOWN: /*specific case for CERT RR*/ + return("????"); +#endif + case DNS_KEY_ALGO_RSAMD5 : return("RSAMD5"); + case DNS_KEY_ALGO_DSA : return("DSA"); + } + return(""); +} + +static u_int16_t +calc_dns_key_tag(X509 *x509) { + /* [RFC 2535] Appendix C: Key Tag Calculation */ + + /* TODO: to be implemented or not ? + * I'm happy without this. + */ + return(1); +} + +static u_int8_t +get_dns_sign_algo(X509 *x509) { + int rsa_algo = DNS_KEY_ALGO_UNKNOWN; + int algo_nid; + + X509_CINF *ci; + X509_ALGOR *sig; + ASN1_OBJECT *alg; + + if (x509 == NULL) goto done; + + ci = x509->cert_info; + if (ci == NULL) goto done; + + sig = ci->signature; + if (sig == NULL) goto done; + + alg = sig->algorithm; + if (alg == NULL) goto done; + + algo_nid = OBJ_obj2nid(alg); + debug3("get_dns_sign_algo: nid=%d(%s)\n", algo_nid, OBJ_nid2ln(algo_nid)); + + switch(algo_nid) { + case NID_md5WithRSAEncryption: + rsa_algo = DNS_KEY_ALGO_RSAMD5; + break; + case NID_sha1WithRSAEncryption: + case NID_md2WithRSAEncryption: + case NID_md4WithRSAEncryption: + case NID_ripemd160WithRSA: + /* not defined in [RFC 2535] ! */ + rsa_algo = DNS_KEY_ALGO_UNKNOWN; + break; + case NID_dsaWithSHA1: + rsa_algo = DNS_KEY_ALGO_DSA; + break; + default: + rsa_algo = DNS_KEY_ALGO_UNKNOWN; + } + +done: + return(rsa_algo); +} + +/* + * Read CERT parameters from key buffer. + */ +static int/*bool*/ +dns_read_cert(ssh_dns_cert_param *param, const Key *key) +{ + int ret = 0; + X509 *x509 = NULL; + BIO *bio = NULL; + int k = 0; + + if (param == NULL) goto done; + if (key == NULL) goto done; + + switch (key->type) { + case KEY_X509_RSA: + case KEY_X509_DSA: { + } break; + default: + goto done; + } + + x509 = key->x509; + if (x509 == NULL) goto done; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) goto done; + + i2d_X509_bio(bio, x509); + BIO_flush(bio); + + cert_param_clean(param); + + k = BIO_pending(bio); + param->cert_data = xmalloc(k + 1); /*fatal on error*/ + param->cert_len = BIO_read(bio, param->cert_data, k); + + k = param->cert_len << 1; + param->b64_data = xmalloc(k); /*fatal on error*/ + param->b64_len = uuencode(param->cert_data, param->cert_len, (char*)param->b64_data, k); + + param->algo = get_dns_sign_algo(x509); + param->key_tag = calc_dns_key_tag(x509); + param->cert_type = DNS_CERT_TYPE_PKIX; + + ret = 1; + +done: + if (bio) BIO_free_all(bio); + return(ret); +} + /* * Read SSHFP parameters from rdata buffer. */ @@ -142,6 +312,126 @@ return success; } +/* + * Read CERT parameters from rdata buffer. + */ +static int/*bool*/ +dns_read_cert_rdata(ssh_dns_cert_param *param, u_char *rdata, int rdata_len) +{ + size_t len ; + + cert_param_clean(param); + + if (rdata_len < 5) return(0); + + param->cert_type = (rdata[0] << 8) + rdata[1]; + param->key_tag = (rdata[2] << 8) + rdata[3]; + param->algo = rdata[4]; + + len = rdata_len - 5; + param->cert_len = len; + if (len > 0) { + param->cert_data = (u_char *) xmalloc(len); + memcpy(param->cert_data, rdata + 5, len); + } + return(1); +} + +/* + * Verify the given hostname, address and host key using DNS. + * Returns 0 if lookup succeeds, -1 otherwise + */ +static int +verify_hostcert_dns(const char *hostname, const Key *hostkey, int *flags) +{ + int counter; + int result; + struct rrsetinfo *certs = NULL; + + ssh_dns_cert_param hostkey_param; + ssh_dns_cert_param dnskey_param; + + debug3("verify_hostcert_dns"); + + memset(&hostkey_param, 0, sizeof(hostkey_param)); + memset(&dnskey_param , 0, sizeof(dnskey_param )); + + result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, + DNS_RDATATYPE_CERT, 0, &certs); + if (result) { + verbose("DNS lookup error: %s", dns_result_totext(result)); + return(-1); + } + + if (certs->rri_flags & RRSET_VALIDATED) { + *flags |= DNS_VERIFY_SECURE; + debug("found %d secure certificates in DNS", + certs->rri_nrdatas); + } else { + debug("found %d insecure certificates in DNS", + certs->rri_nrdatas); + } + + /* Initialize host key parameters */ + if (!dns_read_cert(&hostkey_param, hostkey)) { + error("Error calculating host key certificate."); + cert_param_clean(&hostkey_param); + freerrset(certs); + return(-1); + } + + if (certs->rri_nrdatas) + *flags |= DNS_VERIFY_FOUND; + + for (counter = 0 ; counter < certs->rri_nrdatas ; counter++) { + Key* dns_cert = NULL; + /* + * Extract the key from the answer. Ignore any badly + * formatted certificates. + */ + if (!dns_read_cert_rdata(&dnskey_param, + certs->rri_rdatas[counter].rdi_data, + certs->rri_rdatas[counter].rdi_length + )) { + verbose("Error parsing certificate from DNS."); + goto next; + } + + if (hostkey_param.cert_type != dnskey_param.cert_type) continue; + + /* We will skip useless "key tag" */ + + /* We will ignore "algorithm" since number of + * algorithms defined in [RFC 2535] is limited. + */ + dns_cert = x509key_from_blob(dnskey_param.cert_data, dnskey_param.cert_len); + if (dns_cert == NULL) { + verbose("Invalid certificate from DNS."); + goto next; + } + if (X509_cmp(hostkey->x509, dns_cert->x509) == 0) { + *flags |= DNS_VERIFY_MATCH; + } + key_free(dns_cert); + dns_cert = NULL; + +next: + cert_param_clean(&dnskey_param); + } + + cert_param_clean(&hostkey_param); + freerrset(certs); + + if (*flags & DNS_VERIFY_FOUND) + if (*flags & DNS_VERIFY_MATCH) + debug("matching host key certificate found in DNS"); + else + debug("mismatching host key certificate found in DNS"); + else + debug("no host key certificate found in DNS"); + + return(0); +} /* * Verify the given hostname, address and host key using DNS. @@ -171,6 +461,14 @@ if (hostkey == NULL) fatal("No key to look up!"); + if ((hostkey->type == KEY_X509_RSA) || (hostkey->type == KEY_X509_DSA)) { + result = verify_hostcert_dns(hostname, hostkey, flags); + if (*flags & DNS_VERIFY_FOUND) { + return(result); + } + /*try to found SSHFP RR*/ + } + result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, DNS_RDATATYPE_SSHFP, 0, &fingerprints); if (result) { @@ -248,10 +546,58 @@ u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; u_char *rdata_digest; u_int rdata_digest_len; + ssh_dns_cert_param cert_param; int i; int success = 0; + memset(&cert_param, 0, sizeof(cert_param)); + + if (dns_read_cert(&cert_param, key)) { + u_char *p; + int k; + + if (generic || (cert_param.algo == DNS_KEY_ALGO_UNKNOWN)) { + fprintf(f, "%s\tIN\tTYPE%d \\# %d %04x %04x %02x (\n\t" + , hostname + , DNS_RDATATYPE_CERT + , 5 + cert_param.cert_len + , cert_param.cert_type + , cert_param.key_tag + , cert_param.algo + ); + p = cert_param.cert_data; + i = cert_param.cert_len; + k = 32; + for (; i > 0; i--, p++) { + fprintf(f, "%02x", (int) *p); + if (--k <= 0) { + fprintf(f, "\n\t"); + k = 32; + } + } + } else { + fprintf(f, "%s\tIN\tCERT\t%s %d %s (\n\t" + , hostname + , bind_cert_type(&cert_param) + , cert_param.key_tag + , bind_key_algo(&cert_param) + ); + p = cert_param.b64_data; + i = cert_param.b64_len; + k = 64; + for (; i > 0; i--, p++) { + fprintf(f, "%c", *p); + if (--k <= 0) { + fprintf(f, "\n\t"); + k = 64; + } + } + } + fprintf(f, "\n\t)\n"); + success = 1; + + } else if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, &rdata_digest, &rdata_digest_len, key)) { @@ -271,5 +617,6 @@ error("dns_export_rr: unsupported algorithm"); } + cert_param_clean(&cert_param); return success; } diff -ruN openssh-3.9p1+x509-5.1/dns.h openssh-3.9p1+x509-5.2/dns.h --- openssh-3.9p1+x509-5.1/dns.h 2003-11-17 12:19:29.000000000 +0200 +++ openssh-3.9p1+x509-5.2/dns.h 2005-06-12 09:06:00.000000000 +0300 @@ -1,9 +1,12 @@ -/* $OpenBSD: dns.h,v 1.5 2003/11/12 16:39:58 jakob Exp $ */ +/* $OpenBSD$ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. * Copyright (c) 2003 Jakob Schlyter. All rights reserved. * + * X.509 certificates support: + * Copyright (c) 2005 Roumen Petrov. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,12 +40,39 @@ SSHFP_KEY_DSA }; +enum dns_cert_types { + DNS_CERT_TYPE_RESERVER = 0, + DNS_CERT_TYPE_PKIX = 1, /* X.509 as per PKIX */ + DNS_CERT_TYPE_SPKI = 2, /* SPKI cert */ + DNS_CERT_TYPE_PGP = 3, /* PGP cert */ +/* 4-252 available for IANA assignment */ + DNS_CERT_TYPE_URI = 253, /* URI private */ + DNS_CERT_TYPE_OID = 254, /* OID private */ +/* 255-65534 available for IANA assignment */ + DNS_CERT_TYPE_RESERVER2 = 65535 +}; + enum sshfp_hashes { SSHFP_HASH_RESERVED, SSHFP_HASH_SHA1 }; +enum dns_key_algo { + DNS_KEY_ALGO_RESERVED = 0, /* reserved, see [RFC 2535] Section 11 */ + DNS_KEY_ALGO_UNKNOWN = 0, /* when algorithm is unknown to a secure DNS [RFC 2538] */ + DNS_KEY_ALGO_RSAMD5 = 1, /* RSA/MD5 [RFC 2537] */ + DNS_KEY_ALGO_DH = 2, /* Diffie-Hellman [RFC 2539] */ + DNS_KEY_ALGO_DSA = 3, /* DSA [RFC 2536] */ + DNS_KEY_ALGO_ECC = 4, /* reserved for elliptic curve crypto */ +/* 5-251 available, see [RFC 2535] Section 11 */ + DNS_KEY_ALGO_INDIRECT = 252, /* reserved for indirect keys */ + DNS_KEY_ALGO_PRIVATEDNS = 253, /* private - domain name (see [RFC 2535]) */ + DNS_KEY_ALGO_PRIVATEOID = 254, /* private - OID (see [RFC 2535]) */ + DNS_KEY_ALGO_RESERVED2 = 255 /* reserved, see [RFC 2535] Section 11 */ +}; + #define DNS_RDATACLASS_IN 1 +#define DNS_RDATATYPE_CERT 37 #define DNS_RDATATYPE_SSHFP 44 #define DNS_VERIFY_FOUND 0x00000001 diff -ruN openssh-3.9p1+x509-5.1/hostfile.c openssh-3.9p1+x509-5.2/hostfile.c --- openssh-3.9p1+x509-5.1/hostfile.c 2004-08-18 19:14:27.000000000 +0300 +++ openssh-3.9p1+x509-5.2/hostfile.c 2005-06-12 09:06:01.000000000 +0300 @@ -13,7 +13,7 @@ * * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. * Copyright (c) 1999 Niels Provos. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/key.c openssh-3.9p1+x509-5.2/key.c --- openssh-3.9p1+x509-5.1/key.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/key.c 2005-06-12 09:06:01.000000000 +0300 @@ -10,7 +10,7 @@ * * * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/key.h openssh-3.9p1+x509-5.2/key.h --- openssh-3.9p1+x509-5.1/key.h 2004-08-18 19:14:27.000000000 +0300 +++ openssh-3.9p1+x509-5.2/key.h 2005-06-12 09:06:00.000000000 +0300 @@ -2,7 +2,7 @@ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/Makefile.in openssh-3.9p1+x509-5.2/Makefile.in --- openssh-3.9p1+x509-5.1/Makefile.in 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/Makefile.in 2005-06-12 09:06:01.000000000 +0300 @@ -392,7 +392,7 @@ tests: check -# Target check is more common for projects using autoXXXX tools +# Target check is more common for the projects using autoXXXX tools check: check-regress check-certs diff -ruN openssh-3.9p1+x509-5.1/myproposal.h openssh-3.9p1+x509-5.2/myproposal.h --- openssh-3.9p1+x509-5.1/myproposal.h 2004-08-18 19:14:27.000000000 +0300 +++ openssh-3.9p1+x509-5.2/myproposal.h 2005-06-12 09:06:00.000000000 +0300 @@ -2,7 +2,7 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/pathnames.h openssh-3.9p1+x509-5.2/pathnames.h --- openssh-3.9p1+x509-5.1/pathnames.h 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/pathnames.h 2005-06-12 09:06:00.000000000 +0300 @@ -11,7 +11,7 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/readconf.c openssh-3.9p1+x509-5.2/readconf.c --- openssh-3.9p1+x509-5.1/readconf.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/readconf.c 2005-06-12 09:06:01.000000000 +0300 @@ -810,6 +810,7 @@ if (strchr(arg, '=') != NULL) fatal("%s line %d: Invalid environment name.", filename, linenum); + if (!*activep) continue; if (options->num_send_env >= MAX_SEND_ENV) fatal("%s line %d: too many send env.", filename, linenum); diff -ruN openssh-3.9p1+x509-5.1/ssh.0 openssh-3.9p1+x509-5.2/ssh.0 --- openssh-3.9p1+x509-5.1/ssh.0 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh.0 2005-06-12 09:06:00.000000000 +0300 @@ -680,7 +680,7 @@ Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and cre- ated OpenSSH. Markus Friedl contributed the support for SSH protocol - versions 1.5 and 2.0. Roumen Petrov contributed support for x509 cer- + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- tificates. BSD September 25, 1999 BSD diff -ruN openssh-3.9p1+x509-5.1/ssh.1 openssh-3.9p1+x509-5.2/ssh.1 --- openssh-3.9p1+x509-5.1/ssh.1 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh.1 2005-06-12 09:06:00.000000000 +0300 @@ -1132,4 +1132,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. -Roumen Petrov contributed support for x509 certificates. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-3.9p1+x509-5.1/ssh-add.c openssh-3.9p1+x509-5.2/ssh-add.c --- openssh-3.9p1+x509-5.1/ssh-add.c 2004-08-18 19:14:28.000000000 +0300 +++ openssh-3.9p1+x509-5.2/ssh-add.c 2005-06-12 09:06:01.000000000 +0300 @@ -12,7 +12,7 @@ * * SSH2 implementation, * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/ssh-agent.0 openssh-3.9p1+x509-5.2/ssh-agent.0 --- openssh-3.9p1+x509-5.1/ssh-agent.0 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-agent.0 2005-06-12 09:06:00.000000000 +0300 @@ -116,7 +116,7 @@ Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and cre- ated OpenSSH. Markus Friedl contributed the support for SSH protocol - versions 1.5 and 2.0. Roumen Petrov contributed support for x509 cer- + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- tificates. BSD September 25, 1999 BSD diff -ruN openssh-3.9p1+x509-5.1/ssh-agent.1 openssh-3.9p1+x509-5.2/ssh-agent.1 --- openssh-3.9p1+x509-5.1/ssh-agent.1 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-agent.1 2005-06-12 09:06:00.000000000 +0300 @@ -212,4 +212,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. -Roumen Petrov contributed support for x509 certificates. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-3.9p1+x509-5.1/ssh-agent.c openssh-3.9p1+x509-5.2/ssh-agent.c --- openssh-3.9p1+x509-5.1/ssh-agent.c 2004-08-18 19:14:28.000000000 +0300 +++ openssh-3.9p1+x509-5.2/ssh-agent.c 2005-06-12 09:06:01.000000000 +0300 @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". * * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/ssh.c openssh-3.9p1+x509-5.2/ssh.c --- openssh-3.9p1+x509-5.1/ssh.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh.c 2005-06-12 09:06:01.000000000 +0300 @@ -18,7 +18,7 @@ * Modified to work with SSL by Niels Provos * in Canada (German citizen). * - * X509 certificates support: + * X.509 certificates support: * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/ssh_config.0 openssh-3.9p1+x509-5.2/ssh_config.0 --- openssh-3.9p1+x509-5.1/ssh_config.0 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh_config.0 2005-06-12 09:06:00.000000000 +0300 @@ -51,7 +51,7 @@ IPv6 only.) AllowedCertPurpose - The intended use for the X509 server certificate. Without this + The intended use for the X.509 server certificate. Without this option no chain verification will be done. Currently accepted uses are case insensitive: o `sslserver' , `SSL server' , `SSL_server' or `server' ; @@ -548,16 +548,16 @@ provider. In use when VAType is set to ``ocspspec''. VerifyHostKeyDNS - Specifies whether to verify the remote key using DNS and SSHFP - resource records. If this option is set to ``yes'', the client - will implicitly trust keys that match a secure fingerprint from - DNS. Insecure fingerprints will be handled as if this option was - set to ``ask''. If this option is set to ``ask'', information on - fingerprint match will be displayed, but the user will still need - to confirm new host keys according to the StrictHostKeyChecking - option. The argument must be ``yes'', ``no'' or ``ask''. The - default is ``no''. Note that this option applies to protocol - version 2 only. + Specifies whether to verify the remote key using DNS and + CERT/SSHFP resource records. If this option is set to ``yes'', + the client will implicitly trust keys that match a secure finger- + print from DNS. Insecure fingerprints will be handled as if this + option was set to ``ask''. If this option is set to ``ask'', + information on fingerprint match will be displayed, but the user + will still need to confirm new host keys according to the + StrictHostKeyChecking option. The argument must be ``yes'', + ``no'' or ``ask''. The default is ``no''. Note that this option + applies to protocol version 2 only. XAuthLocation Specifies the full pathname of the xauth(1) program. The default diff -ruN openssh-3.9p1+x509-5.1/ssh_config.5 openssh-3.9p1+x509-5.2/ssh_config.5 --- openssh-3.9p1+x509-5.1/ssh_config.5 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh_config.5 2005-06-12 09:06:00.000000000 +0300 @@ -125,7 +125,7 @@ .Dq inet6 (Use IPv6 only.) .It Cm AllowedCertPurpose -The intended use for the X509 server certificate. Without this option +The intended use for the X.509 server certificate. Without this option no chain verification will be done. Currently accepted uses are case insensitive: .Bl -bullet -compact @@ -938,7 +938,7 @@ is set to .Dq ocspspec . .It Cm VerifyHostKeyDNS -Specifies whether to verify the remote key using DNS and SSHFP resource +Specifies whether to verify the remote key using DNS and CERT/SSHFP resource records. If this option is set to .Dq yes , diff -ruN openssh-3.9p1+x509-5.1/sshconnect.c openssh-3.9p1+x509-5.2/sshconnect.c --- openssh-3.9p1+x509-5.1/sshconnect.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/sshconnect.c 2005-06-12 09:06:01.000000000 +0300 @@ -11,8 +11,28 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" @@ -799,7 +819,7 @@ break; case HOST_CHANGED: if (options.check_host_ip && host_ip_differ) { - char *key_msg; + const char *key_msg; if (ip_status == HOST_NEW) key_msg = "is unknown"; else if (ip_status == HOST_OK) @@ -939,9 +959,15 @@ if (flags & DNS_VERIFY_MATCH) { matching_host_key_dns = 1; } else { + const char *rr = ""; warn_changed_key(host_key); - error("Update the SSHFP RR in DNS with the new " - "host key to get rid of this message."); + if ((host_key->type == KEY_X509_RSA) || (host_key->type == KEY_X509_DSA)) { + rr = "CERT"; + } else { + rr = "SSHFP"; + } + error("Update the %s RR in DNS with the new " + "host key to get rid of this message.", rr); } } } diff -ruN openssh-3.9p1+x509-5.1/sshd.c openssh-3.9p1+x509-5.2/sshd.c --- openssh-3.9p1+x509-5.1/sshd.c 2004-11-19 09:06:01.000000000 +0200 +++ openssh-3.9p1+x509-5.2/sshd.c 2005-06-12 09:06:01.000000000 +0300 @@ -20,7 +20,7 @@ * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. * - * X509 certificates support: + * X.509 certificates support: * Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/sshd_config.0 openssh-3.9p1+x509-5.2/sshd_config.0 --- openssh-3.9p1+x509-5.1/sshd_config.0 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/sshd_config.0 2005-06-12 09:06:00.000000000 +0300 @@ -29,7 +29,7 @@ any environment variables. AllowedCertPurpose - The intended use for the X509 client certificate. Without this + The intended use for the X.509 client certificate. Without this option no chain verification will be done. Currently accepted uses are case insensitive: o `sslclient' , `SSL client' , `SSL_client' or `client' ; diff -ruN openssh-3.9p1+x509-5.1/sshd_config.5 openssh-3.9p1+x509-5.2/sshd_config.5 --- openssh-3.9p1+x509-5.1/sshd_config.5 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/sshd_config.5 2005-06-12 09:06:00.000000000 +0300 @@ -85,7 +85,7 @@ For this reason, care should be taken in the use of this directive. The default is not to accept any environment variables. .It Cm AllowedCertPurpose -The intended use for the X509 client certificate. Without this option +The intended use for the X.509 client certificate. Without this option no chain verification will be done. Currently accepted uses are case insensitive: .Bl -bullet -compact diff -ruN openssh-3.9p1+x509-5.1/ssh-keygen.0 openssh-3.9p1+x509-5.2/ssh-keygen.0 --- openssh-3.9p1+x509-5.1/ssh-keygen.0 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-keygen.0 2005-06-12 09:06:00.000000000 +0300 @@ -160,7 +160,8 @@ -r hostname Print the SSHFP fingerprint resource record named hostname for - the specified public key file. + the specified public key file. In case of X.509 certificates + print CERT resource record. MODULI GENERATION ssh-keygen may be used to generate groups for the Diffie-Hellman Group @@ -277,7 +278,7 @@ Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and cre- ated OpenSSH. Markus Friedl contributed the support for SSH protocol - versions 1.5 and 2.0. Roumen Petrov contributed support for x509 cer- + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- tificates. BSD September 25, 1999 BSD diff -ruN openssh-3.9p1+x509-5.1/ssh-keygen.1 openssh-3.9p1+x509-5.2/ssh-keygen.1 --- openssh-3.9p1+x509-5.1/ssh-keygen.1 2004-11-19 09:06:00.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-keygen.1 2005-06-12 09:06:00.000000000 +0300 @@ -283,6 +283,7 @@ Print the SSHFP fingerprint resource record named .Ar hostname for the specified public key file. +In case of X.509 certificates print CERT resource record. .El .Sh MODULI GENERATION .Nm @@ -460,4 +461,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. -Roumen Petrov contributed support for x509 certificates. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-3.9p1+x509-5.1/ssh-keyscan.1 openssh-3.9p1+x509-5.2/ssh-keyscan.1 --- openssh-3.9p1+x509-5.1/ssh-keyscan.1 2004-08-18 19:14:28.000000000 +0300 +++ openssh-3.9p1+x509-5.2/ssh-keyscan.1 2005-06-12 09:06:00.000000000 +0300 @@ -6,7 +6,7 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" -.\" X509 certificates support, +.\" X.509 certificates support, .\" Copyright (c) 2002-2003 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/ssh-keyscan.c openssh-3.9p1+x509-5.2/ssh-keyscan.c --- openssh-3.9p1+x509-5.1/ssh-keyscan.c 2004-08-18 19:14:28.000000000 +0300 +++ openssh-3.9p1+x509-5.2/ssh-keyscan.c 2005-06-12 09:06:01.000000000 +0300 @@ -5,7 +5,7 @@ * permitted provided that due credit is given to the author and the * OpenBSD project by leaving this copyright notice intact. * - * X509 certificates support, + * X.509 certificates support, * Copyright (c) 2002-2004 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff -ruN openssh-3.9p1+x509-5.1/ssh-x509.c openssh-3.9p1+x509-5.2/ssh-x509.c --- openssh-3.9p1+x509-5.1/ssh-x509.c 2004-11-07 11:50:38.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-x509.c 2005-06-11 15:03:05.000000000 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2004 Roumen Petrov. All rights reserved. + * Copyright (c) 2002-2005 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #include "x509store.h" #include "compat.h" + int (*pssh_x509cert_check)(X509 *_cert) = NULL; int ssh_X509_NAME_cmp(X509_NAME *_a, X509_NAME *_b); @@ -51,7 +52,7 @@ #ifndef SSH_X509STORE_DISABLED static const char* -x509key_find_subject(int _keytype, const char* s) { +x509key_find_subject(const char* s) { static const char *keywords[] = { "subject", "distinguished name", @@ -64,11 +65,13 @@ const char **q, *p; size_t len; - if (_keytype != KEY_X509_RSA && - _keytype != KEY_X509_DSA) { - debug3("x509key_find_subject: %d is not x509 key ", _keytype); + if (s == NULL) { + error("x509key_find_subject: no input data"); return(NULL); } + for (; *s && isspace((int)*s); s++) + {/*skip space*/} + for (q=keywords; *q; q++) { len = strlen(*q); if (strncasecmp(s, *q, len) != 0) continue; @@ -104,13 +107,40 @@ #ifndef SSH_X509STORE_DISABLED -static int +static int/*bool*/ +ssh_X509_NAME_add_entry_by_NID(X509_NAME* name, int nid, const char* str, size_t len) { + int ret = 0; + + /*this is internal method and we don't check validity of arguments*/ + + ret = X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (u_char*)str, (int)len, -1, 0); + if (!ret) { + char ebuf[256]; + error("ssh_X509_NAME_add_entry_by_NID: X509_NAME_add_entry_by_NID" + " fail with errormsg='%.*s'" + " for nid=%d/%.32s" + " and data='%.128s'" + , sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf)) + , nid, OBJ_nid2ln(nid) + , str); + } + return(ret); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifndef SSH_X509STORE_DISABLED +static int/*bool*/ x509key_str2X509NAME(const char* _str, X509_NAME *_name) { int ret = 1; + char *str = NULL; char *p, *q, *token; - char ch; + int has_more = 0; + + str = xmalloc(strlen(_str) + 1); /*fatal on error*/ + strcpy(str, _str); - p = (char*)_str; + p = (char*)str; while (*p) { int nid; for (; *p && isspace((int)*p); p++) @@ -131,10 +161,10 @@ } } if (token) { - ch = *token; + has_more = 1; *token = 0; } else { - ch = 0; + has_more = 0; token = p + strlen(p); } q = strchr(p, '='); @@ -153,43 +183,33 @@ } } #endif /* def SSH_OPENSSL_DN_WITHOUT_EMAIL */ - *q = '='; if (nid == NID_undef) { error("x509key_str2X509NAME: cannot get nid from string '%.200s'", p); ret = 0; - } else { - p = q + 1; - if (!*p) { - error("x509key_str2X509NAME: no data"); - ret = 0; - } else { /* add */ - char save; - for (q = token - 1; (q >= p) && isspace((int)*q); q--) - {/*skip unexpected \n, etc. from end*/} - - save = *++q; - *q = 0; - ret = X509_NAME_add_entry_by_NID(_name, nid, MBSTRING_ASC, (u_char*)p, q - p, -1, 0); - if (ret <= 0) { - char ebuf[256]; - error("x509key_str2X509NAME: X509_NAME_add_entry_by_NID" - " fail with errormsg='%.256s'" - " for nid=%d/%.32s" - " and data='%.128s'" - , openssl_errormsg(ebuf, sizeof(ebuf)) - , nid, OBJ_nid2ln(nid) - , p); - } - *q = save; - } + break; } - *token = ch; - if (ret <= 0) { + + p = q + 1; + if (!*p) { + error("x509key_str2X509NAME: no data"); + ret = 0; break; } + + for (q = token - 1; (q >= p) && isspace((int)*q); q--) + {/*skip unexpected \n, etc. from end*/} + *++q = 0; + + ret = ssh_X509_NAME_add_entry_by_NID(_name, nid, p, (size_t)(q - p)); + if (!ret) { + break; + } + p = token; - if (*p) p++; + if (has_more) p++; } + + if (str) xfree(str); debug3("x509key_str2X509NAME: return %d", ret); return(ret); } @@ -198,18 +218,24 @@ #ifndef SSH_X509STORE_DISABLED Key* -x509key_from_subject(int _keytype, char* _cp) { +x509key_from_subject(int _keytype, const char* _cp) { int ret = 1; Key* key = NULL; X509_NAME *subj; const char *subject; - debug3("x509key_from_subject(%d, [%.200s]) called ", _keytype, _cp); - subject = x509key_find_subject(_keytype, _cp); + if (_keytype != KEY_X509_RSA && + _keytype != KEY_X509_DSA) { + debug3("x509key_from_subject: %d is not x509 key ", _keytype); + return(NULL); + } + debug3("x509key_from_subject(%d, [%.*s]) called ", + _keytype, X509_NAME_MAXLEN, (_cp ? _cp : "")); + subject = x509key_find_subject(_cp); if (subject == NULL) return(NULL); - debug3("x509key_from_subject: subject=[%.200s]", subject); + debug3("x509key_from_subject: subject=[%.*s]", X509_NAME_MAXLEN, subject); key = key_new(_keytype); if (key == NULL) { error("x509key_from_subject: out of memory"); @@ -248,8 +274,8 @@ env_pkey = X509_get_pubkey(x509); if (env_pkey == NULL) { char ebuf[256]; - error("x509_to_key: X509_get_pubkey fail %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + error("x509_to_key: X509_get_pubkey fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); return(NULL); } /*else*/ @@ -307,8 +333,8 @@ * If data contain x506 certificate blob we will return a key otherwise NULL. */ char ebuf[256]; - debug3("x509key_from_blob: read X509 from BIO fail %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + debug3("x509key_from_blob: read X509 from BIO fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); } else { key = x509_to_key(x509); if (key == NULL) @@ -436,8 +462,8 @@ key->x509 = PEM_read_X509(fp, NULL, NULL, NULL); if (key->x509 == NULL) { char ebuf[256]; - debug3("x509key_load_cert: PEM_read_X509 fail %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + debug3("x509key_load_cert: PEM_read_X509 fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); } else { key->type = (key->type == KEY_RSA) ? KEY_X509_RSA : KEY_X509_DSA; @@ -482,8 +508,8 @@ ret = PEM_write_bio_X509(out, x509); if (!ret) { char ebuf[256]; - error("x509key_save_cert: PEM_write_bio_X509 fail %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + error("x509key_save_cert: PEM_write_bio_X509 fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); } BIO_free_all(out); @@ -544,35 +570,36 @@ #ifndef SSH_X509STORE_DISABLED -/* from RFC2459 +/* from RFC3280 and oldest RFC2459 * (d) attribute values in PrintableString are compared after * removing leading and trailing white space and converting internal * substrings of one or more consecutive white space characters to a * single space. */ static int -ssh_ASN1_PRINTABLESTRING_casecmp(const ASN1_STRING *a, const ASN1_STRING *b) +ssh_printable_casecmp(const u_char *pa, int la, const u_char *pb, int lb) { - int la = M_ASN1_STRING_length(a); - u_char *pa = M_ASN1_STRING_data(a); - int lb = M_ASN1_STRING_length(b); - u_char *pb = M_ASN1_STRING_data(b); - +/* + * Be careful: this method work fine only in "C(POSIX)" locale. + * Since OpenSSH now run without to set locale, i.e. + * following comparision is OK. + * This implementation should be changed for other locales !!! + */ /* skip leading spaces */ - for (; la > 0 && isspace(*pa); la--, pa++); - for (; lb > 0 && isspace(*pb); lb--, pb++); + for (; la > 0 && isspace((int)*pa); la--, pa++); + for (; lb > 0 && isspace((int)*pb); lb--, pb++); /* skip trailing spaces */ { - u_char *p; - for (p = pa + la - 1; la > 0 && isspace(*p); la--, p--); - for (p = pb + lb - 1; lb > 0 && isspace(*p); lb--, p--); + const u_char *p; + for (p = pa + la - 1; la > 0 && isspace((int)*p); la--, p--); + for (p = pb + lb - 1; lb > 0 && isspace((int)*p); lb--, p--); } while (la > 0 && lb > 0) { - int chA = tolower(*pa); - int chB = tolower(*pb); + int chA = tolower((int)*pa); + int chB = tolower((int)*pb); if (chA != chB) return(chB - chA); @@ -580,8 +607,8 @@ pa++; pb++; la--; lb--; if (isspace(chA)) { - for (; la > 0 && isspace(*pa); la--, pa++); - for (; lb > 0 && isspace(*pb); lb--, pb++); + for (; la > 0 && isspace((int)*pa); la--, pa++); + for (; lb > 0 && isspace((int)*pb); lb--, pb++); } } return(lb - la); @@ -590,13 +617,49 @@ #ifndef SSH_X509STORE_DISABLED +static int +ssh_ASN1_PRINTABLESTRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + int n = -1; + int tagA, tagB; + int la, lb; + u_char *pa, *pb; + + tagA = M_ASN1_STRING_type(a); + tagB = M_ASN1_STRING_type(b); + if (tagA != V_ASN1_PRINTABLESTRING) { + debug3("ssh_ASN1_PRINTABLESTRING_cmp: a->type=%d(%.30s) is not PrintableString", tagA, ASN1_tag2str(tagA)); + } + if (tagB != V_ASN1_PRINTABLESTRING) { + debug3("ssh_ASN1_PRINTABLESTRING_cmp: b->type=%d(%.30s) is not PrintableString", tagB, ASN1_tag2str(tagB)); + } + + /* TODO when tagA == tagB */ + /*both are PrintableString*/ + la = M_ASN1_STRING_length(a); + pa = M_ASN1_STRING_data(a); + lb = M_ASN1_STRING_length(b); + pb = M_ASN1_STRING_data(b); + /* TODO else */ + /*convert strings to utf8*/ + + n = ssh_printable_casecmp(pa, la, pb, lb); +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_ASN1_PRINTABLESTRING_cmp: return %d\n", n); +#endif + return(n); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifndef SSH_X509STORE_DISABLED /* * 1.) * Since version 0.9.7.beta4 and 0.9.6h OpenSSL function X509_NAME_cmp * is more restrictive but more correct (!). * Problem is that some x509 implementation set X509_NAME entry * incorrectly to "Printable String" :-[ . - * O.K. when one entry is "Printable String" we will compare + * Work around: when one entry is "Printable String" method compare * to corresponding entry as "Printable String". * 2.) * OpenSSL functions X509_NAME_cmp check nids order in X509_NAME. @@ -660,14 +723,21 @@ trynextentry: neB = sk_X509_NAME_ENTRY_value(b->entries, loc); nvB = neB->value; -#ifdef SSHX509TEST +#ifdef SSHX509TEST_DBGCMP { - int la = M_ASN1_STRING_length(nvA); - u_char *pa = M_ASN1_STRING_data (nvA); - int lb = M_ASN1_STRING_length(nvB); - u_char *pb = M_ASN1_STRING_data (nvB); + int l, tag; - logit("nvA='%*s', nvB='%*s'", la, pa, lb, pb); + l = M_ASN1_STRING_length(nvA); + tag = M_ASN1_STRING_type (nvA); + fprintf(stderr, "nvA(%.40s:%d)='", ASN1_tag2str(tag), l); + ASN1_STRING_print_ex_fp(stderr, nvA, /*flags*/0); + fputs("'\n", stderr); + + l = M_ASN1_STRING_length(nvB); + tag = M_ASN1_STRING_type (nvB); + fprintf(stderr, "nvA(%.40s:%d)='", ASN1_tag2str(tag), l); + ASN1_STRING_print_ex_fp(stderr, nvB, /*flags*/0); + fputs("'\n", stderr); } #endif @@ -699,17 +769,7 @@ } if ((M_ASN1_STRING_type(nvA) == V_ASN1_PRINTABLESTRING) || (M_ASN1_STRING_type(nvB) == V_ASN1_PRINTABLESTRING) ) { - int tag; - - tag = M_ASN1_STRING_type(nvA); - if (tag != V_ASN1_PRINTABLESTRING) - debug("ssh_X509_NAME_cmp: X509_NAME_ENTRY(a)->type=%d(%.30s) is not PrintableString", tag, ASN1_tag2str(tag)); - - tag = M_ASN1_STRING_type(nvB); - if (tag != V_ASN1_PRINTABLESTRING) - debug("ssh_X509_NAME_cmp: X509_NAME_ENTRY(b)->type=%d(%.30s) is not PrintableString", tag, ASN1_tag2str(tag)); - - n = ssh_ASN1_PRINTABLESTRING_casecmp(nvA, nvB); + n = ssh_ASN1_PRINTABLESTRING_cmp(nvA, nvB); if (n == 0) goto entryisok; goto getnextentry; @@ -741,6 +801,9 @@ } X509_NAME_free(b); +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_X509_NAME_cmp: return %d\n", n); +#endif return(n); } #endif /*ndef SSH_X509STORE_DISABLED*/ @@ -806,8 +869,8 @@ if (ret <= 0) { char ebuf[256]; - error("ssh_x509_sign: EVP_PKEY_set1_XXX: failed %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + error("ssh_x509_sign: EVP_PKEY_set1_XXX: failed %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); } } @@ -832,8 +895,8 @@ ret = EVP_SignFinal(&ctx, sigret, &siglen, privkey); if (ret <= 0) { char ebuf[256]; - error("ssh_x509_sign: digest failed: %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + error("ssh_x509_sign: digest failed: %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); } } } @@ -954,8 +1017,8 @@ } if (ret <= 0) { char ebuf[256]; - error("ssh_x509_verify: verify failed: %.256s", - openssl_errormsg(ebuf, sizeof(ebuf))); + error("ssh_x509_verify: verify failed: %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); ret = 0; } } diff -ruN openssh-3.9p1+x509-5.1/ssh-x509.h openssh-3.9p1+x509-5.2/ssh-x509.h --- openssh-3.9p1+x509-5.1/ssh-x509.h 2004-11-07 11:52:52.000000000 +0200 +++ openssh-3.9p1+x509-5.2/ssh-x509.h 2005-06-10 21:01:46.000000000 +0300 @@ -33,7 +33,7 @@ /* * Method return a key(x509) only with "Subject"("Distinguished Name") ! */ -Key* x509key_from_subject(int _keytype, char* _cp); +Key* x509key_from_subject(int _keytype, const char* _cp); #endif /*ndef SSH_X509STORE_DISABLED*/ diff -ruN openssh-3.9p1+x509-5.1/tests/CA/3-cre_certs.sh openssh-3.9p1+x509-5.2/tests/CA/3-cre_certs.sh --- openssh-3.9p1+x509-5.1/tests/CA/3-cre_certs.sh 2004-03-20 12:54:08.000000000 +0200 +++ openssh-3.9p1+x509-5.2/tests/CA/3-cre_certs.sh 2005-06-03 00:00:11.000000000 +0300 @@ -41,7 +41,7 @@ test "x$TEST_SSH_SSHKEYGEN" = "x" && { echo "Please define TEST_SSH_SSHKEYGEN"; exit 1; } test -z "$1" && usage -while ! test -z "$1"; do +while test -n "$1"; do case $1 in -f|\ -file) @@ -49,7 +49,7 @@ if test -z "$1"; then usage fi - if ! test -z "${SSH_BASE_KEY}"; then + if test -n "${SSH_BASE_KEY}"; then usage fi SSH_BASE_KEY="$1" @@ -62,7 +62,7 @@ if test -z "$1"; then usage fi - if ! test -z "$SSH_CERT_TYPE"; then + if test -n "$SSH_CERT_TYPE"; then usage fi SSH_CERT_TYPE="$1" @@ -95,7 +95,7 @@ if test -z "$1"; then usage fi - if ! test -z "${SSH_BASE_DN_CN}"; then + if test -n "${SSH_BASE_DN_CN}"; then usage fi SSH_BASE_DN_CN="$1" diff -ruN openssh-3.9p1+x509-5.1/tests/CA/functions openssh-3.9p1+x509-5.2/tests/CA/functions --- openssh-3.9p1+x509-5.1/tests/CA/functions 2004-10-02 00:22:16.000000000 +0300 +++ openssh-3.9p1+x509-5.2/tests/CA/functions 2005-05-30 22:28:13.000000000 +0300 @@ -108,7 +108,7 @@ # === show_status () { - if ! test -z "$2"; then + if test -n "$2"; then printf '%s' "$2" fi if test $1 -eq 0; then diff -ruN openssh-3.9p1+x509-5.1/tests/CA/Makefile.in openssh-3.9p1+x509-5.2/tests/CA/Makefile.in --- openssh-3.9p1+x509-5.1/tests/CA/Makefile.in 2004-11-07 10:49:37.000000000 +0200 +++ openssh-3.9p1+x509-5.2/tests/CA/Makefile.in 2005-06-02 22:20:11.000000000 +0300 @@ -1,6 +1,7 @@ srcdir=@srcdir@ @OCSP_ON@SSH_OCSP=yes @OCSP_OFF@SSH_OCSP=no +KEYBITS=1024 all: @@ -47,7 +48,7 @@ testhostkey_rsa: @echo @echo "generating RSA 'hostkey'" - $(TEST_SSH_SSHKEYGEN) -t rsa -b 1024 -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" testhostkey_rsa-rsa_md5: testhostkey_rsa ca-test/catest-bundle.crt @echo @@ -57,7 +58,7 @@ testhostkey_dsa: @echo @echo "generating DSA 'hostkey'" - $(TEST_SSH_SSHKEYGEN) -t dsa -b 1024 -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" testhostkey_dsa-rsa_md5: testhostkey_dsa ca-test/catest-bundle.crt @echo @@ -71,7 +72,7 @@ testid_rsa: @echo @echo "generating RSA 'Identity'" - $(TEST_SSH_SSHKEYGEN) -t rsa -b 1024 -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" testid_rsa-rsa_md5: testid_rsa ca-test/catest-bundle.crt @echo @@ -81,7 +82,7 @@ testid_dsa: @echo @echo "generating DSA 'Identity'" - $(TEST_SSH_SSHKEYGEN) -t dsa -b 1024 -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" testid_dsa-rsa_md5: testid_dsa ca-test/catest-bundle.crt @echo @@ -100,7 +101,7 @@ @OCSP_ON@testocsp_rsa: @OCSP_ON@ @echo; echo "generating RSA 'ocspkey'" -@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t rsa -b 1024 -f $@ -N "" +@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" @OCSP_ON@testocsp_dsa-rsa_md5.crt: testocsp_dsa ca-test/catest-bundle.crt @OCSP_ON@ @echo; echo "generating DSA ocsp responder certificates." @@ -109,7 +110,7 @@ @OCSP_ON@testocsp_dsa: @OCSP_ON@ @echo; echo "generating DSA 'ocspkey'" -@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t dsa -b 1024 -f $@ -N "" +@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" # === diff -ruN openssh-3.9p1+x509-5.1/tests/CA/openssh_tests.sh openssh-3.9p1+x509-5.2/tests/CA/openssh_tests.sh --- openssh-3.9p1+x509-5.1/tests/CA/openssh_tests.sh 2004-11-11 00:15:10.000000000 +0200 +++ openssh-3.9p1+x509-5.2/tests/CA/openssh_tests.sh 2005-06-02 22:11:08.000000000 +0300 @@ -290,15 +290,17 @@ cat "${SSH_ERRLOG}"; printf '%s' "${norm}" else if test "x$must_fail" = "x1"; then - if ! fgrep 'Permission denied (publickey)' "${SSH_ERRLOG}" > /dev/null; then + if fgrep 'Permission denied (publickey)' "${SSH_ERRLOG}" > /dev/null; then + printf '%s' "${done}" + else retval=33 printf '%s' "${warn}" - else - printf '%s' "${done}" fi cat "${SSH_ERRLOG}"; printf '%s' "${norm}" else - if ! fgrep "$msg" "${SSH_REPLY}" > /dev/null; then + if fgrep "$msg" "${SSH_REPLY}" > /dev/null; then + : + else retval=33 printf '%s' "${warn}" cat "${SSH_REPLY}"; printf '%s' "${norm}" diff -ruN openssh-3.9p1+x509-5.1/x509store.c openssh-3.9p1+x509-5.2/x509store.c --- openssh-3.9p1+x509-5.1/x509store.c 2004-11-15 23:36:10.000000000 +0200 +++ openssh-3.9p1+x509-5.2/x509store.c 2005-06-02 22:22:03.000000000 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2004 Roumen Petrov. All rights reserved. + * Copyright (c) 2002-2005 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,12 @@ #include "misc.h" #include "openssl/err.h" #include "openssl/x509_vfy.h" +/* struct X509_VERIFY_PARAM is defined in OpenSSL 0.9.8x */ +#ifdef HAVE_X509_STORE_CTX_PARAM +# define SSH_X509_VERIFY_PARAM(ctx,member) ctx->param->member +#else +# define SSH_X509_VERIFY_PARAM(ctx,member) ctx->member +#endif #ifdef LDAP_ENABLED # include "x509_by_ldap.h" #endif @@ -625,10 +631,31 @@ #ifndef SSH_X509STORE_DISABLED #ifdef SSH_CHECK_REVOKED +static void +ssh_get_namestr_and_hash( + X509_NAME *name, + char *buf, + size_t len, + u_long *hash +) { + if (name == NULL) { + debug("ssh_get_namestr_and_hash: name is NULL"); + if (buf ) *buf = '\0'; + if (hash) *hash = 0; /* not correct but :-( */ + return; + } + + if (buf ) X509_NAME_oneline(name, buf, len); + if (hash) *hash = X509_NAME_hash(name); +} + + static int/*bool*/ ssh_check_crl(X509_STORE_CTX *_ctx, X509* _issuer, X509_CRL *_crl) { time_t *pcheck_time; int k; + char buf[X509_NAME_MAXLEN]; + u_long hash; if (_issuer == NULL) { error("ssh_check_crl: issuer is NULL"); @@ -641,7 +668,6 @@ if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { BIO *bio; - char buf[X509_NAME_MAXLEN]; char *p; bio = BIO_new(BIO_s_mem()); @@ -678,12 +704,13 @@ if (/*???(_issuer->ex_flags & EXFLAG_KUSAGE) &&*/ !(_issuer->ex_kusage & KU_CRL_SIGN) ) { - char buf[X509_NAME_MAXLEN]; - - X509_NAME_oneline(X509_get_subject_name(_issuer), buf, sizeof(buf)); - error("ssh_check_crl: to verify crl signature key usage 'cRLSign'" - " must present in issuer certificate '%.*s'" - , (int) sizeof(buf), buf); + ssh_get_namestr_and_hash(X509_get_subject_name(_issuer), buf, sizeof(buf), &hash); + error("ssh_check_crl:" + " to verify crl signature key usage 'cRLSign'" + " must present in issuer certificate '%.*s' with hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); #ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN /*first defined in OpenSSL 0.9.7d*/ X509_STORE_CTX_set_error(_ctx, X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); @@ -700,7 +727,12 @@ } if (X509_CRL_verify(_crl, pkey) <= 0) { - error("ssh_check_crl: CRL has invalid signature"); + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), buf, sizeof(buf), &hash); + error("ssh_check_crl: CRL has invalid signature" + ": issuer='%.*s', hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); return(0); } @@ -708,31 +740,63 @@ } - if (_ctx->flags & X509_V_FLAG_USE_CHECK_TIME) - pcheck_time = &_ctx->check_time; + if (SSH_X509_VERIFY_PARAM(_ctx,flags) & X509_V_FLAG_USE_CHECK_TIME) + pcheck_time = &SSH_X509_VERIFY_PARAM(_ctx,check_time); else pcheck_time = NULL; k = X509_cmp_time(X509_CRL_get_lastUpdate(_crl), pcheck_time); if (k == 0) { + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), buf, sizeof(buf), &hash); + error("ssh_check_crl: CRL has invalid lastUpdate field" + ": issuer='%.*s', hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); X509_STORE_CTX_set_error(_ctx, X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); - error("ssh_check_crl: CRL has invalid lastUpdate field"); return(0); } if (k > 0) { + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), buf, sizeof(buf), &hash); + error("ssh_check_crl: CRL is not yet valid" + ": issuer='%.*s', hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_NOT_YET_VALID); - error("ssh_check_crl: CRL is not yet valid"); return(0); } k = X509_cmp_time(X509_CRL_get_nextUpdate(_crl), pcheck_time); if (k == 0) { - error("ssh_check_crl: CRL has invalid nextUpdate field"); + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), buf, sizeof(buf), &hash); + error("ssh_check_crl: CRL has invalid nextUpdate field" + ": issuer='%.*s', hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); X509_STORE_CTX_set_error(_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); return(0); } +#if 0 + /*test "extend time limit"*/ + if (k < 0) { + time_t tm; + if (pcheck_time == NULL) { + tm = time(NULL); + pcheck_time = &tm; + } + *pcheck_time -= convtime("1w"); + k = X509_cmp_time(X509_CRL_get_nextUpdate(_crl), pcheck_time); + } +#endif if (k < 0) { - error("ssh_check_crl: CRL is expired"); + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), buf, sizeof(buf), &hash); + error("ssh_check_crl: CRL is expired" + ": issuer='%.*s', hash=0x%08lx" + , (int) sizeof(buf), buf + , hash + ); X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_HAS_EXPIRED); return(0); }