diff -ruN openssh-4.2p1/aclocal.m4 openssh-4.2p1+x509-5.5/aclocal.m4 --- openssh-4.2p1/aclocal.m4 2001-10-22 03:53:59.000000000 +0300 +++ openssh-4.2p1+x509-5.5/aclocal.m4 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -dnl $Id: aclocal.m4,v 1.5 2001/10/22 00:53:59 tim Exp $ +dnl $Id$ dnl dnl OpenSSH-specific autoconf macros dnl @@ -84,3 +84,198 @@ #include ]) ]) + +# Options to build with LDAP +# +# Author: Roumen Petrov +# Revision: 19 Jul 2005 +# +dnl The variables provided are : +dnl - build flags: +dnl LDAP_LDFLAGS +dnl LDAP_LIBS +dnl LDAP_CPPFLAGS +dnl - conditional: +dnl LDAP_ON (e.g. '' or '#') +dnl LDAP_OFF (e.g. '#' or '' - oposite of LDAP_ON) +dnl - paths: +dnl LDAP_BINDIR +dnl LDAP_LIBEXECDIR +dnl LDAP_SYSCONFDIR + +AC_DEFUN(AC_WITH_LDAP, +[ +dnl +dnl Get the ldap paths +dnl + +ac_ldap='none' +AC_ARG_ENABLE(ldap, + [ --enable-ldap Enable LDAP queries], + ac_ldap="$enableval" +) + +if test "x$ac_ldap" = xyes; then + ac_ldap_prefix="" + AC_ARG_WITH(ldap-prefix, + [ --with-ldap-prefix=PATH Prefix where LDAP is installed (optional)], + ac_ldap_prefix="$withval" + ) + + AC_ARG_WITH(ldap-bindir, + [ --with-ldap-bindir=PATH Prefix where LDAP user executables are installed (optional)], + [LDAP_BINDIR="$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_BINDIR="$ac_ldap_prefix/bin" + fi + ] + ) + AC_SUBST(LDAP_BINDIR) + + AC_ARG_WITH(ldap-libexecdir, + [ --with-ldap-libexecdir=PATH Prefix where LDAP program executables are installed (optional)], + [LDAP_LIBEXECDIR="$withval"], + [ + if test "x$ac_ldap_prefix" = "x"; then + LDAP_LIBEXECDIR="/usr/libexec" + else + LDAP_LIBEXECDIR="$ac_ldap_prefix/libexec" + fi + ] + ) + AC_SUBST(LDAP_LIBEXECDIR) +dnl### Check for slapd +dnl if test "x$cross_compiling" = "xyes" ; then +dnl AC_MSG_NOTICE([cannot check for LDAP daemon when cross compiling]) +dnl else +dnl AC_CHECK_FILES( +dnl [ +dnl $LDAP_LIBEXECDIR/slapd +dnl ] +dnl ) +dnl fi + + AC_ARG_WITH(ldap-sysconfdir, + [ --with-ldap-sysconfdir=PATH Prefix where LDAP single-machine data are installed (optional)], + [LDAP_SYSCONFDIR="$withval"], + [LDAP_SYSCONFDIR="$ac_ldap_prefix/etc/openldap"] + ) + AC_SUBST(LDAP_SYSCONFDIR) +dnl### Check for schema files +dnl if test "x$cross_compiling" = "xyes" ; then +dnl AC_MSG_NOTICE([cannot check for schema files existence when cross compiling]) +dnl else +dnl AC_CHECK_FILES( +dnl [ +dnl $LDAP_SYSCONFDIR/schema/core.schema +dnl $LDAP_SYSCONFDIR/schema/cosine.schema +dnl $LDAP_SYSCONFDIR/schema/inetorgperson.schema +dnl ] +dnl ) +dnl fi + + + AC_ARG_WITH(ldap-libdir, + [ --with-ldap-libdir=PATH Prefix where LDAP libaries are installed (optional)], + [LDAP_LDFLAGS="-L$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_LDFLAGS="-L$ac_ldap_prefix/lib" + else + LDAP_LDFLAGS="" + fi + ] + ) + AC_SUBST(LDAP_LDFLAGS) + + AC_ARG_WITH(ldap-includedir, + [ --with-ldap-includedir=PATH Prefix where LDAP header files are installed (optional)], + [LDAP_CPPFLAGS="-I$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_CPPFLAGS="-I$ac_ldap_prefix/include" + else + LDAP_CPPFLAGS="" + fi + ] + ) + AC_SUBST(LDAP_CPPFLAGS) + + + ac_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + AC_CHECK_HEADERS( + [lber.h ldap.h], + [], + [ + AC_MSG_ERROR([cannot found LDAP headers]) + ] + ) + CPPFLAGS="$ac_save_CPPFLAGS" + + ac_ldap_libs="" + AC_ARG_WITH(ldap-libs, + [ --with-ldap-libs=LIBS Specify LDAP libraries to link with. + (default is -lldap -llber -lssl -lcrypto)], + [ac_ldap_libs="$withval"] + ) + +### Try to link with LDAP libs + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + + LDFLAGS="$LDAP_LDFLAGS $LDFLAGS" + ac_LDAP_LINK="" + if test "x$ac_ldap_libs" != "x"; then + AC_MSG_CHECKING([to link with specified LDAP libs]) + + LDAP_LIBS="$ac_ldap_libs" + LIBS="$LDAP_LIBS $ac_save_LIBS" + AC_LINK_IFELSE( + [AC_LANG_CALL([], [ldap_init])], + [ac_LDAP_LINK="yes"] + ) + if test "x$ac_LDAP_LINK" != "xyes"; then + AC_MSG_ERROR([cannot link with specified LDAP libs]) + fi + else + AC_MSG_CHECKING([how to link LDAP libs]) + + LDAP_LIBS="-lldap" + for L in lber ssl crypto; do + LDAP_LIBS="$LDAP_LIBS -l$L" + LIBS="$LDAP_LIBS $ac_save_LIBS" + AC_LINK_IFELSE( + [AC_LANG_CALL([], [ldap_init])], + [ac_LDAP_LINK="yes"] + ) + if test "x$ac_LDAP_LINK" = "xyes"; then + break + fi + done + if test "x$ac_LDAP_LINK" != "xyes"; then + AC_MSG_ERROR([cannot link with default LDAP libs]) + fi + fi + AC_MSG_RESULT([done]) + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + AC_SUBST([LDAP_LIBS]) +else + AC_MSG_NOTICE([LDAP is disabled]) +fi + +if test "x$ac_ldap" = "xyes"; then + AC_DEFINE_UNQUOTED( + LDAP_ENABLED, 1, + [Define if you want to enable LDAP queries]) + LDAP_ON='' + LDAP_OFF='#' +else + LDAP_ON='#' + LDAP_OFF='' +fi +AC_SUBST(LDAP_ON) +AC_SUBST(LDAP_OFF) +]) diff -ruN openssh-4.2p1/auth2-hostbased.c openssh-4.2p1+x509-5.5/auth2-hostbased.c --- openssh-4.2p1/auth2-hostbased.c 2004-01-21 02:02:50.000000000 +0200 +++ openssh-4.2p1+x509-5.5/auth2-hostbased.c 2005-09-02 09:06:01.000000000 +0300 @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2-hostbased.c,v 1.6 2004/01/19 21:25:15 markus Exp $"); +RCSID("$OpenBSD$"); #include "ssh2.h" #include "xmalloc.h" @@ -44,6 +44,8 @@ extern u_char *session_id2; extern u_int session_id2_len; +static int hostbased_algorithm_allowed(int pktype); + static int userauth_hostbased(Authctxt *authctxt) { @@ -81,6 +83,11 @@ "public key algorithm: %s", pkalg); goto done; } + if (!hostbased_algorithm_allowed(pktype)) { + debug("userauth_hostbased: disallowed " + "public key algorithm: %s", pkalg); + goto done; + } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_hostbased: cannot decode key: %s", pkalg); @@ -127,6 +134,28 @@ return authenticated; } +/* return 1 if given hostbased algorithm is allowed */ +static int +hostbased_algorithm_allowed(int pktype) +{ + char *s, *cp, *p; + + if (options.hostbased_algorithms == NULL) return(1); + + s = cp = xstrdup(options.hostbased_algorithms); + for (p = strsep(&cp, ","); + p && *p != '\0'; + p = strsep(&cp, ",") + ) { + if (pktype == key_type_from_name(p)) { + xfree(s); + return(1); + } + } + xfree(s); + return(0); +} + /* return 1 if given hostkey is allowed */ int hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, diff -ruN openssh-4.2p1/auth2-pubkey.c openssh-4.2p1+x509-5.5/auth2-pubkey.c --- openssh-4.2p1/auth2-pubkey.c 2004-12-11 04:39:50.000000000 +0200 +++ openssh-4.2p1+x509-5.5/auth2-pubkey.c 2006-04-26 09:06:01.000000000 +0300 @@ -1,5 +1,7 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. + * X.509 certificates support, + * Copyright (c) 2003-2006 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,7 +25,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2-pubkey.c,v 1.9 2004/12/11 01:48:56 dtucker Exp $"); +RCSID("$OpenBSD$"); #include "ssh.h" #include "ssh2.h" @@ -41,6 +43,7 @@ #include "auth-options.h" #include "canohost.h" #include "monitor_wrap.h" +#include "ssh-x509.h" #include "misc.h" /* import */ @@ -48,6 +51,8 @@ extern u_char *session_id2; extern u_int session_id2_len; +static int pubkey_algorithm_allowed(int pktype); + static int userauth_pubkey(Authctxt *authctxt) { @@ -84,6 +89,11 @@ pkalg); goto done; } + if (!pubkey_algorithm_allowed(pktype)) { + debug("userauth_pubkey: disallowed public key algorithm: %s", + pkalg); + goto done; + } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); @@ -165,6 +175,121 @@ return authenticated; } +/* return 1 if given publickey algorithm is allowed */ +static int +pubkey_algorithm_allowed(int pktype) +{ + char *s, *cp, *p; + + if (options.pubkey_algorithms == NULL) return(1); + + s = cp = xstrdup(options.pubkey_algorithms); + for (p = strsep(&cp, ","); + p && *p != '\0'; + p = strsep(&cp, ",") + ) { + if (pktype == key_type_from_name(p)) { + xfree(s); + return(1); + } + } + xfree(s); + return(0); +} + +static int +key_readx(Key *ret, char **cpp) { + int flag; + + flag = key_read(ret, cpp); + if (flag == 1) return(1); + + switch (ret->type) { + case KEY_X509_RSA: + debug3("pubkey key_readx(RSA)"); + ret->type = KEY_RSA; + flag = key_read(ret, cpp); + break; + case KEY_X509_DSA: + debug3("pubkey key_readx(DSA)"); + ret->type = KEY_DSA; + flag = key_read(ret, cpp); + break; + } + return(flag); +} + +static int +key_match(const Key *key, const Key *found) { + if (key == NULL || found == NULL) + return(0); + + if (key->type == found->type) { +#ifdef SSH_X509STORE_DISABLED + return(key_equal(key, found)); +#else /*ndef SSH_X509STORE_DISABLED*/ + if (!key_equal(key, found)) + return(0); + + /* + * Key are equal but in case of certificates + * when x509store is enabled found key may + * contain only distinguished name. + */ + if ((found->type != KEY_X509_RSA) && + (found->type != KEY_X509_DSA)) + return(1); + + debug3("key_match:found matching certificate"); + if (!options.x509flags->key_allow_selfissued) { + /* + * Only the verification process can + * allow the received certificate. + */ + return(1); + } + + /* + * The public key or certificate found in + * autorized keys file can allow self-issued. + */ + if (!ssh_is_selfsigned(key->x509)) + return(1); + + debug3("key_match:self-signed certificate"); + options.x509flags->key_allow_selfissued = 0; + if (ssh_x509cert_check(key->x509) == 1) { + /* the certificated is trusted by x509store */ + options.x509flags->key_allow_selfissued = 1; + return(1); + } + options.x509flags->key_allow_selfissued = 1; + + /* the certificate can be allowed by public key */ +#endif /*ndef SSH_X509STORE_DISABLED*/ + } + + if ((key->type == KEY_X509_RSA) && + ((found->type == KEY_RSA) || (found->type == KEY_X509_RSA)) + ) { + debug3("key_match:RSA"); + return(key->rsa != NULL && found->rsa != NULL && + BN_cmp(key->rsa->e, found->rsa->e) == 0 && + BN_cmp(key->rsa->n, found->rsa->n) == 0); + } + if ((key->type == KEY_X509_DSA) && + ((found->type == KEY_DSA) || (found->type == KEY_X509_DSA)) + ) { + debug3("key_match:DSA"); + return(key->dsa != NULL && found->dsa != NULL && + BN_cmp(key->dsa->p, found->dsa->p) == 0 && + BN_cmp(key->dsa->q, found->dsa->q) == 0 && + BN_cmp(key->dsa->g, found->dsa->g) == 0 && + BN_cmp(key->dsa->pub_key, found->dsa->pub_key) == 0); + } + return(0); +} + /* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) @@ -215,7 +340,8 @@ if (!*cp || *cp == '\n' || *cp == '#') continue; - if (key_read(found, &cp) != 1) { + found->type = key->type; + if (key_readx(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); @@ -229,20 +355,33 @@ /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; - if (key_read(found, &cp) != 1) { + found->type = key->type; + if (key_readx(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } - if (key_equal(found, key) && + if (key_match(key, found) && auth_parse_options(pw, key_options, file, linenum) == 1) { found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); - fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); + /* Variable key always contain public key or + * certificate. In case of X.509 certificate + * x509 attribute of Key structure "found" + * can contain only "Distinguished Name" ! + */ + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); + if ((key->type == KEY_X509_RSA) || + (key->type == KEY_X509_DSA)) { + if (ssh_x509cert_check(key->x509) != 1) { + found_key = 0; + verbose("x509 certificate check reject matching key"); + } + } xfree(fp); break; } diff -ruN openssh-4.2p1/authfd.c openssh-4.2p1+x509-5.5/authfd.c --- openssh-4.2p1/authfd.c 2005-06-17 05:59:35.000000000 +0300 +++ openssh-4.2p1+x509-5.5/authfd.c 2005-09-02 09:06:01.000000000 +0300 @@ -12,6 +12,8 @@ * * SSH2 implementation, * Copyright (c) 2000 Markus Friedl. All rights reserved. + * X509 certificate support, + * Copyright (c) 2002 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.66 2005/06/17 02:44:32 djm Exp $"); +RCSID("$OpenBSD$"); #include @@ -466,6 +468,7 @@ buffer_put_cstring(b, key_ssh_name(key)); switch (key->type) { case KEY_RSA: + case KEY_X509_RSA: buffer_put_bignum2(b, key->rsa->n); buffer_put_bignum2(b, key->rsa->e); buffer_put_bignum2(b, key->rsa->d); @@ -474,6 +477,7 @@ buffer_put_bignum2(b, key->rsa->q); break; case KEY_DSA: + case KEY_X509_DSA: buffer_put_bignum2(b, key->dsa->p); buffer_put_bignum2(b, key->dsa->q); buffer_put_bignum2(b, key->dsa->g); @@ -481,6 +485,21 @@ buffer_put_bignum2(b, key->dsa->priv_key); break; } + if ((key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA)) { + int len; + void* str; + unsigned char *p; + + len = i2d_X509(key->x509, NULL); + str = xmalloc(len); + if (str == NULL) + { error("ssh_encode_identity_ssh2: out of memory"); return; } + + p = str; + i2d_X509(key->x509, &p); + buffer_put_string(b, str, len); + xfree(str); + } buffer_put_cstring(b, comment); } @@ -508,6 +527,8 @@ break; case KEY_RSA: case KEY_DSA: + case KEY_X509_RSA: + case KEY_X509_DSA: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; @@ -562,7 +583,7 @@ buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); - } else if (key->type == KEY_DSA || key->type == KEY_RSA) { + } else if (key->type == KEY_DSA || key->type == KEY_RSA || key->type == KEY_X509_DSA || key->type == KEY_X509_RSA ) { key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); diff -ruN openssh-4.2p1/authfile.c openssh-4.2p1+x509-5.5/authfile.c --- openssh-4.2p1/authfile.c 2005-06-17 05:59:35.000000000 +0300 +++ openssh-4.2p1+x509-5.5/authfile.c 2006-04-26 09:06:01.000000000 +0300 @@ -13,6 +13,8 @@ * * * Copyright (c) 2000 Markus Friedl. All rights reserved. + * X509 certificate support, + * Copyright (c) 2002-2006 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +38,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.61 2005/06/17 02:44:32 djm Exp $"); +RCSID("$OpenBSD$"); #include #include @@ -51,6 +53,7 @@ #include "log.h" #include "authfile.h" #include "rsa.h" +#include "ssh-x509.h" #include "misc.h" #include "atomicio.h" @@ -198,6 +201,10 @@ success = PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + success = x509key_save_pem(fp, key, cipher, passphrase, len); + break; } fclose(fp); return success; @@ -214,6 +221,8 @@ break; case KEY_DSA: case KEY_RSA: + case KEY_X509_RSA: + case KEY_X509_DSA: return key_save_private_pem(key, filename, passphrase, comment); break; @@ -460,6 +469,7 @@ Key *prv = NULL; char *name = ""; + debug("read PEM private key begin"); fp = fdopen(fd, "r"); if (fp == NULL) { error("fdopen failed: %s", strerror(errno)); @@ -497,6 +507,14 @@ error("PEM_read_PrivateKey: mismatch or " "unknown EVP_PKEY save_type %d", pk->save_type); } + if (prv) { + x509key_load_cert(prv, fp); + if (prv->x509 != NULL) { + if (!X509_check_private_key(prv->x509, pk)) { + fatal("X509 certificate don't match private key"); + } + } + } fclose(fp); if (pk != NULL) EVP_PKEY_free(pk); @@ -644,6 +662,7 @@ char file[MAXPATHLEN]; /* try rsa1 private key */ + debug3("key_load_public(%.200s,...)", filename); pub = key_load_public_type(KEY_RSA1, filename, commentp); if (pub != NULL) return pub; diff -ruN openssh-4.2p1/compat.c openssh-4.2p1+x509-5.5/compat.c --- openssh-4.2p1/compat.c 2005-03-01 12:24:33.000000000 +0200 +++ openssh-4.2p1+x509-5.5/compat.c 2006-01-15 09:06:01.000000000 +0200 @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.71 2005/03/01 10:09:52 djm Exp $"); +RCSID("$OpenBSD: compat.c,v 1.70 2003/11/02 11:01:03 markus Exp $"); #include "buffer.h" #include "packet.h" diff -ruN openssh-4.2p1/compat.h openssh-4.2p1+x509-5.5/compat.h --- openssh-4.2p1/compat.h 2005-03-01 12:24:33.000000000 +0200 +++ openssh-4.2p1+x509-5.5/compat.h 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: compat.h,v 1.39 2005/03/01 10:09:52 djm Exp $ */ +/* $OpenBSD: compat.h,v 1.38 2004/07/11 17:48:47 deraadt Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. diff -ruN openssh-4.2p1/config.h.in openssh-4.2p1+x509-5.5/config.h.in --- openssh-4.2p1/config.h.in 2005-09-01 12:15:22.000000000 +0300 +++ openssh-4.2p1+x509-5.5/config.h.in 2005-09-02 09:06:01.000000000 +0300 @@ -699,6 +699,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LASTLOG_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LBER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LDAP_H + /* Define to 1 if you have the `bsm' library (-lbsm). */ #undef HAVE_LIBBSM @@ -789,6 +795,9 @@ /* Define to 1 if you have the `nsleep' function. */ #undef HAVE_NSLEEP +/* Define to 1 if you have the `OCSP_sendreq_bio' function. */ +#undef HAVE_OCSP_SENDREQ_BIO + /* Define to 1 if you have the `ogetaddrinfo' function. */ #undef HAVE_OGETADDRINFO @@ -1119,6 +1128,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 @@ -1134,6 +1146,9 @@ /* Define to 1 if you have the `__b64_pton' function. */ #undef HAVE___B64_PTON +/* Define if you want to enable LDAP queries */ +#undef LDAP_ENABLED + /* max value of long long calculated by configure */ #undef LLONG_MAX @@ -1176,9 +1191,22 @@ /* The size of a `short int', as computed by sizeof. */ #undef SIZEOF_SHORT_INT +/* Specify location of ssh CA root */ +#undef SSHCADIR + /* Use audit debugging module */ #undef SSH_AUDIT_EVENTS +/* Define if you don't want to validate X.509 certificates with OCSP */ +#undef SSH_OCSP_ENABLED + +/* Define if your openssl library don't support Email in X.509 'Distinguished + Name' */ +#undef SSH_OPENSSL_DN_WITHOUT_EMAIL + +/* Define if you don't want to verify certificates */ +#undef SSH_X509STORE_DISABLED + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS diff -ruN openssh-4.2p1/configure openssh-4.2p1+x509-5.5/configure --- openssh-4.2p1/configure 2005-09-01 12:15:24.000000000 +0300 +++ openssh-4.2p1+x509-5.5/configure 2006-04-26 09:06:02.000000000 +0300 @@ -311,7 +311,7 @@ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os AWK CPP RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR CAT KILL PERL SED ENT TEST_MINUS_S_SH SH TEST_SHELL PATH_GROUPADD_PROG PATH_USERADD_PROG MAKE_PACKAGE_SUPPORTED LOGIN_PROGRAM_FALLBACK PATH_PASSWD_PROG LD EGREP LIBWRAP LIBEDIT LIBPAM INSTALL_SSH_RAND_HELPER SSH_PRIVSEP_USER PROG_LS PROG_NETSTAT PROG_ARP PROG_IFCONFIG PROG_JSTAT PROG_PS PROG_SAR PROG_W PROG_WHO PROG_LAST PROG_LASTLOG PROG_DF PROG_VMSTAT PROG_UPTIME PROG_IPCS PROG_TAIL INSTALL_SSH_PRNG_CMDS OPENSC_CONFIG PRIVSEP_PATH xauth_path STRIP_OPT XAUTH_PATH NROFF MANTYPE mansubdir user_path piddir LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os AWK CPP RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR CAT KILL PERL SED ENT TEST_MINUS_S_SH SH TEST_SHELL PATH_GROUPADD_PROG PATH_USERADD_PROG MAKE_PACKAGE_SUPPORTED LOGIN_PROGRAM_FALLBACK PATH_PASSWD_PROG LD EGREP LIBWRAP LIBEDIT LIBPAM INSTALL_SSH_RAND_HELPER SSH_PRIVSEP_USER PROG_LS PROG_NETSTAT PROG_ARP PROG_IFCONFIG PROG_JSTAT PROG_PS PROG_SAR PROG_W PROG_WHO PROG_LAST PROG_LASTLOG PROG_DF PROG_VMSTAT PROG_UPTIME PROG_IPCS PROG_TAIL INSTALL_SSH_PRNG_CMDS OPENSC_CONFIG PRIVSEP_PATH xauth_path STRIP_OPT XAUTH_PATH NROFF MANTYPE mansubdir user_path sshcadir OCSP_ON OCSP_OFF LDAP_BINDIR LDAP_LIBEXECDIR LDAP_SYSCONFDIR LDAP_LDFLAGS LDAP_CPPFLAGS LDAP_LIBS LDAP_ON LDAP_OFF piddir LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -851,6 +851,9 @@ --disable-largefile omit support for large files --disable-strip Disable calling strip(1) on install --disable-etc-default-login Disable using PATH from /etc/default/login no + --disable-x509store Disable X.509 store + --enable-ocsp Enable OCSP validation + --enable-ldap Enable LDAP queries --disable-lastlog disable use of lastlog even if detected no --disable-utmp disable use of utmp even if detected no --disable-utmpx disable use of utmpx even if detected no @@ -896,6 +899,15 @@ --with-superuser-path= Specify different path for super-user --with-4in6 Check for and convert IPv4 in IPv6 mapped addresses --with-bsd-auth Enable BSD auth support + --with-sshca-dir=PATH Specify location of ssh CA root + --with-ldap-prefix=PATH Prefix where LDAP is installed (optional) + --with-ldap-bindir=PATH Prefix where LDAP user executables are installed (optional) + --with-ldap-libexecdir=PATH Prefix where LDAP program executables are installed (optional) + --with-ldap-sysconfdir=PATH Prefix where LDAP single-machine data are installed (optional) + --with-ldap-libdir=PATH Prefix where LDAP libaries are installed (optional) + --with-ldap-includedir=PATH Prefix where LDAP header files are installed (optional) + --with-ldap-libs=LIBS Specify LDAP libraries to link with. + (default is -lldap -llber -lssl -lcrypto) --with-pid-dir=PATH Specify location of ssh.pid file --with-lastlog=FILE|DIR specify lastlog location common locations @@ -24837,6 +24849,985 @@ fi; +# X.509 support +ssh_x509="yes" +# Reserved for future use +#AC_DEFINE_UNQUOTED( +# X509_DISABLED, 1, +# [Define if you want to disable X.509 certificates]) + +# Where to place ssh CA root +sshcadir='${sysconfdir}/ca' +sshcadir=`eval echo ${sshcadir}` +sshcadir=`eval echo ${sshcadir}` +case $sshcadir in + NONE/*) sshcadir=`echo $sshcadir | sed "s~NONE~$ac_default_prefix~"` ;; +esac + + +# Check whether --with-sshca-dir or --without-sshca-dir was given. +if test "${with_sshca_dir+set}" = set; then + withval="$with_sshca_dir" + + if test "x$withval" != "xno" ; then + sshcadir=$withval + fi + + +fi; + + +cat >>confdefs.h <<_ACEOF +#define SSHCADIR "$sshcadir" +_ACEOF + + + + +ssh_x509store="yes" +# Check whether --enable-x509store or --disable-x509store was given. +if test "${enable_x509store+set}" = set; then + enableval="$enable_x509store" + + if test "x$enableval" = "xno"; then + ssh_x509store="no" + fi + + +fi; +if test "x$ssh_x509store" = "xno"; then + +cat >>confdefs.h <<_ACEOF +#define SSH_X509STORE_DISABLED 1 +_ACEOF + +fi + + +ssh_ocsp="no" +# Check whether --enable-ocsp or --disable-ocsp was given. +if test "${enable_ocsp+set}" = set; then + enableval="$enable_ocsp" + + if test "x$enableval" = "xyes"; then + if test "x$ssh_x509store" = "xyes"; then + ssh_ocsp="yes" + else + { { echo "$as_me:$LINENO: error: cannot enable OCSP when x509store is disabled" >&5 +echo "$as_me: error: cannot enable OCSP when x509store is disabled" >&2;} + { (exit 1); exit 1; }; } + fi + fi + + +fi; +if test "x$ssh_ocsp" = "xyes"; then + +for ac_func in OCSP_sendreq_bio +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+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. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 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_exeext' + { (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 + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + + if test "${ac_cv_header_openssl_ocsp_h+set}" = set; then + echo "$as_me:$LINENO: checking for openssl/ocsp.h" >&5 +echo $ECHO_N "checking for openssl/ocsp.h... $ECHO_C" >&6 +if test "${ac_cv_header_openssl_ocsp_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_openssl_ocsp_h" >&5 +echo "${ECHO_T}$ac_cv_header_openssl_ocsp_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking openssl/ocsp.h usability" >&5 +echo $ECHO_N "checking openssl/ocsp.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_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_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking openssl/ocsp.h presence" >&5 +echo $ECHO_N "checking openssl/ocsp.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 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); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ocsp.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: openssl/ocsp.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to openssh-unix-dev@mindrot.org ## +## ------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for openssl/ocsp.h" >&5 +echo $ECHO_N "checking for openssl/ocsp.h... $ECHO_C" >&6 +if test "${ac_cv_header_openssl_ocsp_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_openssl_ocsp_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_openssl_ocsp_h" >&5 +echo "${ECHO_T}$ac_cv_header_openssl_ocsp_h" >&6 + +fi +if test $ac_cv_header_openssl_ocsp_h = yes; then + : +else + + ssh_ocsp="no" + { { echo "$as_me:$LINENO: error: OCSP header not found" >&5 +echo "$as_me: error: OCSP header not found" >&2;} + { (exit 1); exit 1; }; } + +fi + + + +else + + ssh_ocsp="no" + { echo "$as_me:$LINENO: WARNING: Cannot find OCSP functions - OCSP is disabled" >&5 +echo "$as_me: WARNING: Cannot find OCSP functions - OCSP is disabled" >&2;} + +fi +done + +fi +if test "x$ssh_ocsp" = "xyes"; then + +cat >>confdefs.h <<_ACEOF +#define SSH_OCSP_ENABLED 1 +_ACEOF + + OCSP_ON='' + OCSP_OFF='#' +else + OCSP_ON='#' + OCSP_OFF='' +fi + + + + +# enable LDAP queries +LDAP_MSG="no" +if test "x$ssh_x509store" = "xyes"; then + + +ac_ldap='none' +# Check whether --enable-ldap or --disable-ldap was given. +if test "${enable_ldap+set}" = set; then + enableval="$enable_ldap" + ac_ldap="$enableval" + +fi; + +if test "x$ac_ldap" = xyes; then + ac_ldap_prefix="" + +# Check whether --with-ldap-prefix or --without-ldap-prefix was given. +if test "${with_ldap_prefix+set}" = set; then + withval="$with_ldap_prefix" + ac_ldap_prefix="$withval" + +fi; + + +# Check whether --with-ldap-bindir or --without-ldap-bindir was given. +if test "${with_ldap_bindir+set}" = set; then + withval="$with_ldap_bindir" + LDAP_BINDIR="$withval" +else + + if test "x$ac_ldap_prefix" != "x"; then + LDAP_BINDIR="$ac_ldap_prefix/bin" + fi + + +fi; + + + +# Check whether --with-ldap-libexecdir or --without-ldap-libexecdir was given. +if test "${with_ldap_libexecdir+set}" = set; then + withval="$with_ldap_libexecdir" + LDAP_LIBEXECDIR="$withval" +else + + if test "x$ac_ldap_prefix" = "x"; then + LDAP_LIBEXECDIR="/usr/libexec" + else + LDAP_LIBEXECDIR="$ac_ldap_prefix/libexec" + fi + + +fi; + + + +# Check whether --with-ldap-sysconfdir or --without-ldap-sysconfdir was given. +if test "${with_ldap_sysconfdir+set}" = set; then + withval="$with_ldap_sysconfdir" + LDAP_SYSCONFDIR="$withval" +else + LDAP_SYSCONFDIR="$ac_ldap_prefix/etc/openldap" + +fi; + + + + +# Check whether --with-ldap-libdir or --without-ldap-libdir was given. +if test "${with_ldap_libdir+set}" = set; then + withval="$with_ldap_libdir" + LDAP_LDFLAGS="-L$withval" +else + + if test "x$ac_ldap_prefix" != "x"; then + LDAP_LDFLAGS="-L$ac_ldap_prefix/lib" + else + LDAP_LDFLAGS="" + fi + + +fi; + + + +# Check whether --with-ldap-includedir or --without-ldap-includedir was given. +if test "${with_ldap_includedir+set}" = set; then + withval="$with_ldap_includedir" + LDAP_CPPFLAGS="-I$withval" +else + + if test "x$ac_ldap_prefix" != "x"; then + LDAP_CPPFLAGS="-I$ac_ldap_prefix/include" + else + LDAP_CPPFLAGS="" + fi + + +fi; + + + + ac_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + + +for ac_header in lber.h ldap.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_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_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 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); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to openssh-unix-dev@mindrot.org ## +## ------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + + { { echo "$as_me:$LINENO: error: cannot found LDAP headers" >&5 +echo "$as_me: error: cannot found LDAP headers" >&2;} + { (exit 1); exit 1; }; } + + +fi + +done + + CPPFLAGS="$ac_save_CPPFLAGS" + + ac_ldap_libs="" + +# Check whether --with-ldap-libs or --without-ldap-libs was given. +if test "${with_ldap_libs+set}" = set; then + withval="$with_ldap_libs" + ac_ldap_libs="$withval" + +fi; + +### Try to link with LDAP libs + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + + LDFLAGS="$LDAP_LDFLAGS $LDFLAGS" + ac_LDAP_LINK="" + if test "x$ac_ldap_libs" != "x"; then + echo "$as_me:$LINENO: checking to link with specified LDAP libs" >&5 +echo $ECHO_N "checking to link with specified LDAP libs... $ECHO_C" >&6 + + LDAP_LIBS="$ac_ldap_libs" + LIBS="$LDAP_LIBS $ac_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ldap_init (); +int +main () +{ +ldap_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 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_exeext' + { (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_LDAP_LINK="yes" + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "x$ac_LDAP_LINK" != "xyes"; then + { { echo "$as_me:$LINENO: error: cannot link with specified LDAP libs" >&5 +echo "$as_me: error: cannot link with specified LDAP libs" >&2;} + { (exit 1); exit 1; }; } + fi + else + echo "$as_me:$LINENO: checking how to link LDAP libs" >&5 +echo $ECHO_N "checking how to link LDAP libs... $ECHO_C" >&6 + + LDAP_LIBS="-lldap" + for L in lber ssl crypto; do + LDAP_LIBS="$LDAP_LIBS -l$L" + LIBS="$LDAP_LIBS $ac_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ldap_init (); +int +main () +{ +ldap_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 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_exeext' + { (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_LDAP_LINK="yes" + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "x$ac_LDAP_LINK" = "xyes"; then + break + fi + done + if test "x$ac_LDAP_LINK" != "xyes"; then + { { echo "$as_me:$LINENO: error: cannot link with default LDAP libs" >&5 +echo "$as_me: error: cannot link with default LDAP libs" >&2;} + { (exit 1); exit 1; }; } + fi + fi + echo "$as_me:$LINENO: result: done" >&5 +echo "${ECHO_T}done" >&6 + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + +else + { echo "$as_me:$LINENO: LDAP is disabled" >&5 +echo "$as_me: LDAP is disabled" >&6;} +fi + +if test "x$ac_ldap" = "xyes"; then + +cat >>confdefs.h <<_ACEOF +#define LDAP_ENABLED 1 +_ACEOF + + LDAP_ON='' + LDAP_OFF='#' +else + LDAP_ON='#' + LDAP_OFF='' +fi + + + + if test "x$LDAP_ON" = "x"; then + LDAP_MSG="yes" + fi +else + { echo "$as_me:$LINENO: x509store is disabled - skiping LDAP" >&5 +echo "$as_me: x509store is disabled - skiping LDAP" >&6;} +fi + + +ssh_x509dn_email="yes" +if test "x$ssh_x509store" = "xyes"; then + # Check for Email in X.509 'Distinguished Name' + echo "$as_me:$LINENO: checking for Email in X.509 'Distinguished Name'" >&5 +echo $ECHO_N "checking for Email in X.509 'Distinguished Name'... $ECHO_C" >&6 + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +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(void) { + int nid; + nid = OBJ_txt2nid("Email"); + if (nid == NID_undef) + exit (1); + exit (0); + return (0); +} + +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (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 + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) + + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ssh_x509dn_email="no" + + +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 + +cat >>confdefs.h <<_ACEOF +#define SSH_OPENSSL_DN_WITHOUT_EMAIL 1 +_ACEOF + +fi + # Where to place sshd.pid piddir=/var/run # make sure the directory exists @@ -25463,7 +26454,7 @@ CFLAGS="$CFLAGS $werror_flags" - ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openbsd-compat/Makefile scard/Makefile ssh_prng_cmds survey.sh" + ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openbsd-compat/Makefile scard/Makefile ssh_prng_cmds tests/CA/Makefile tests/CA/env survey.sh" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -25821,9 +26812,9 @@ exec 5>>config.log { echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <&5 cat >&5 <<_CSEOF @@ -25996,6 +26987,8 @@ "openbsd-compat/Makefile" ) CONFIG_FILES="$CONFIG_FILES openbsd-compat/Makefile" ;; "scard/Makefile" ) CONFIG_FILES="$CONFIG_FILES scard/Makefile" ;; "ssh_prng_cmds" ) CONFIG_FILES="$CONFIG_FILES ssh_prng_cmds" ;; + "tests/CA/Makefile" ) CONFIG_FILES="$CONFIG_FILES tests/CA/Makefile" ;; + "tests/CA/env" ) CONFIG_FILES="$CONFIG_FILES tests/CA/env" ;; "survey.sh" ) CONFIG_FILES="$CONFIG_FILES survey.sh" ;; "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 @@ -26151,6 +27144,17 @@ s,@MANTYPE@,$MANTYPE,;t t s,@mansubdir@,$mansubdir,;t t s,@user_path@,$user_path,;t t +s,@sshcadir@,$sshcadir,;t t +s,@OCSP_ON@,$OCSP_ON,;t t +s,@OCSP_OFF@,$OCSP_OFF,;t t +s,@LDAP_BINDIR@,$LDAP_BINDIR,;t t +s,@LDAP_LIBEXECDIR@,$LDAP_LIBEXECDIR,;t t +s,@LDAP_SYSCONFDIR@,$LDAP_SYSCONFDIR,;t t +s,@LDAP_LDFLAGS@,$LDAP_LDFLAGS,;t t +s,@LDAP_CPPFLAGS@,$LDAP_CPPFLAGS,;t t +s,@LDAP_LIBS@,$LDAP_LIBS,;t t +s,@LDAP_ON@,$LDAP_ON,;t t +s,@LDAP_OFF@,$LDAP_OFF,;t t s,@piddir@,$piddir,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t @@ -26665,6 +27669,7 @@ echo " User binaries: $B" echo " System binaries: $C" echo " Configuration files: $D" +echo " CA root: $sshcadir" echo " Askpass program: $E" echo " Manual pages: $F" echo " PID file: $G" @@ -26689,6 +27694,9 @@ echo " S/KEY support: $SKEY_MSG" echo " TCP Wrappers support: $TCPW_MSG" echo " MD5 password support: $MD5_MSG" +echo " X.509 store support: $ssh_x509store" +echo " OCSP support: $ssh_ocsp" +echo " LDAP queries: $LDAP_MSG" echo " libedit support: $LIBEDIT_MSG" echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" @@ -26714,6 +27722,20 @@ echo "" fi +if test "x$LDAP_MSG" = "xyes" ; then +echo "Extra LDAP flags:" +echo " LDAP compiler flags: ${LDAP_CFLAGS}" +echo "LDAP preprocessor flags: ${LDAP_CPPFLAGS}" +echo " LDAP linker flags: ${LDAP_LDFLAGS}" +echo " LDAP libraries: ${LDAP_LIBS}" +echo "" +echo "LDAP paths(used only in tests):" +echo " LDAP sysconfig dir: ${LDAP_SYSCONFDIR}" +echo " LDAP libexec dir: ${LDAP_LIBEXECDIR}" +echo " LDAP bin dir: ${LDAP_BINDIR}" +echo "" +fi + if test "x$PAM_MSG" = "xyes" ; then echo "PAM is enabled. You may need to install a PAM control file " echo "for sshd, otherwise password authentication may fail. " diff -ruN openssh-4.2p1/configure.ac openssh-4.2p1+x509-5.5/configure.ac --- openssh-4.2p1/configure.ac 2005-08-31 19:59:49.000000000 +0300 +++ openssh-4.2p1+x509-5.5/configure.ac 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -# $Id: configure.ac,v 1.292 2005/08/31 16:59:49 tim Exp $ +# $Id$ # # Copyright (c) 1999-2004 Damien Miller # @@ -3111,6 +3111,138 @@ ] ) +# X.509 support +ssh_x509="yes" +# Reserved for future use +#AC_DEFINE_UNQUOTED( +# X509_DISABLED, 1, +# [Define if you want to disable X.509 certificates]) + +# Where to place ssh CA root +sshcadir='${sysconfdir}/ca' +sshcadir=`eval echo ${sshcadir}` +sshcadir=`eval echo ${sshcadir}` +case $sshcadir in + NONE/*) sshcadir=`echo $sshcadir | sed "s~NONE~$ac_default_prefix~"` ;; +esac + +AC_ARG_WITH(sshca-dir, + [ --with-sshca-dir=PATH Specify location of ssh CA root], + [ + if test "x$withval" != "xno" ; then + sshcadir=$withval + fi + ] +) + +AC_DEFINE_UNQUOTED(SSHCADIR, "$sshcadir", [Specify location of ssh CA root]) +AC_SUBST(sshcadir) + + +ssh_x509store="yes" +AC_ARG_ENABLE(x509store, + [ --disable-x509store Disable X.509 store], + [ + if test "x$enableval" = "xno"; then + ssh_x509store="no" + fi + ] +) +if test "x$ssh_x509store" = "xno"; then + AC_DEFINE_UNQUOTED( + SSH_X509STORE_DISABLED, 1, + [Define if you don't want to verify certificates]) +fi + + +ssh_ocsp="no" +AC_ARG_ENABLE(ocsp, + [ --enable-ocsp Enable OCSP validation], + [ + if test "x$enableval" = "xyes"; then + if test "x$ssh_x509store" = "xyes"; then + ssh_ocsp="yes" + else + AC_MSG_ERROR([cannot enable OCSP when x509store is disabled]) + fi + fi + ] +) +if test "x$ssh_ocsp" = "xyes"; then + AC_CHECK_FUNCS(OCSP_sendreq_bio, + [ + AC_CHECK_HEADER(openssl/ocsp.h, + [], + [ + ssh_ocsp="no" + AC_MSG_ERROR([OCSP header not found]) + ]) + ], + [ + ssh_ocsp="no" + AC_MSG_WARN([Cannot find OCSP functions - OCSP is disabled]) + ]) +fi +if test "x$ssh_ocsp" = "xyes"; then + AC_DEFINE_UNQUOTED( + SSH_OCSP_ENABLED, 1, + [Define if you don't want to validate X.509 certificates with OCSP]) + OCSP_ON='' + OCSP_OFF='#' +else + OCSP_ON='#' + OCSP_OFF='' +fi +AC_SUBST(OCSP_ON) +AC_SUBST(OCSP_OFF) + + +# enable LDAP queries +LDAP_MSG="no" +if test "x$ssh_x509store" = "xyes"; then + AC_WITH_LDAP + if test "x$LDAP_ON" = "x"; then + LDAP_MSG="yes" + fi +else + AC_MSG_NOTICE([x509store is disabled - skiping LDAP]) +fi + + +ssh_x509dn_email="yes" +if test "x$ssh_x509store" = "xyes"; then + # Check for Email in X.509 'Distinguished Name' + AC_MSG_CHECKING([for Email in X.509 'Distinguished Name']) + AC_TRY_RUN( + [ +#include + +int main(void) { + int nid; + nid = OBJ_txt2nid("Email"); + if (nid == NID_undef) + exit (1); + exit (0); + return (0); +} + ], + [ + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + 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( + SSH_OPENSSL_DN_WITHOUT_EMAIL, 1, + [Define if your openssl library don't support Email in X.509 'Distinguished Name']) +fi + # Where to place sshd.pid piddir=/var/run # make sure the directory exists @@ -3409,7 +3541,7 @@ AC_EXEEXT AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openbsd-compat/Makefile \ - scard/Makefile ssh_prng_cmds survey.sh]) + scard/Makefile ssh_prng_cmds tests/CA/Makefile tests/CA/env survey.sh]) AC_OUTPUT # Print summary of options @@ -3431,6 +3563,7 @@ echo " User binaries: $B" echo " System binaries: $C" echo " Configuration files: $D" +echo " CA root: $sshcadir" echo " Askpass program: $E" echo " Manual pages: $F" echo " PID file: $G" @@ -3455,6 +3588,9 @@ echo " S/KEY support: $SKEY_MSG" echo " TCP Wrappers support: $TCPW_MSG" echo " MD5 password support: $MD5_MSG" +echo " X.509 store support: $ssh_x509store" +echo " OCSP support: $ssh_ocsp" +echo " LDAP queries: $LDAP_MSG" echo " libedit support: $LIBEDIT_MSG" echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" @@ -3480,6 +3616,20 @@ echo "" fi +if test "x$LDAP_MSG" = "xyes" ; then +echo "Extra LDAP flags:" +echo " LDAP compiler flags: ${LDAP_CFLAGS}" +echo "LDAP preprocessor flags: ${LDAP_CPPFLAGS}" +echo " LDAP linker flags: ${LDAP_LDFLAGS}" +echo " LDAP libraries: ${LDAP_LIBS}" +echo "" +echo "LDAP paths(used only in tests):" +echo " LDAP sysconfig dir: ${LDAP_SYSCONFDIR}" +echo " LDAP libexec dir: ${LDAP_LIBEXECDIR}" +echo " LDAP bin dir: ${LDAP_BINDIR}" +echo "" +fi + if test "x$PAM_MSG" = "xyes" ; then echo "PAM is enabled. You may need to install a PAM control file " echo "for sshd, otherwise password authentication may fail. " diff -ruN openssh-4.2p1/dns.c openssh-4.2p1+x509-5.5/dns.c --- openssh-4.2p1/dns.c 2005-06-17 05:59:35.000000000 +0300 +++ openssh-4.2p1+x509-5.5/dns.c 2006-01-15 09:06:01.000000000 +0200 @@ -1,9 +1,12 @@ -/* $OpenBSD: dns.c,v 1.12 2005/06/17 02:44:32 djm 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.12 2005/06/17 02:44:32 djm 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. */ @@ -164,6 +334,127 @@ } /* + * 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) +{ + u_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. * Returns 0 if lookup succeeds, -1 otherwise */ @@ -196,6 +487,14 @@ return -1; } + 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) { @@ -273,10 +572,57 @@ u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; u_char *rdata_digest; u_int rdata_digest_len; + ssh_dns_cert_param cert_param; u_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)) { @@ -296,5 +642,6 @@ error("dns_export_rr: unsupported algorithm"); } + cert_param_clean(&cert_param); return success; } diff -ruN openssh-4.2p1/dns.h openssh-4.2p1+x509-5.5/dns.h --- openssh-4.2p1/dns.h 2003-11-17 12:19:29.000000000 +0200 +++ openssh-4.2p1+x509-5.5/dns.h 2005-09-02 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-4.2p1/hostfile.c openssh-4.2p1+x509-5.5/hostfile.c --- openssh-4.2p1/hostfile.c 2005-08-02 10:07:08.000000000 +0300 +++ openssh-4.2p1+x509-5.5/hostfile.c 2005-09-02 09:06:01.000000000 +0300 @@ -13,6 +13,8 @@ * * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. * Copyright (c) 1999 Niels Provos. All rights reserved. + * 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 @@ -36,7 +38,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.35 2005/07/27 10:39:03 dtucker Exp $"); +RCSID("$OpenBSD$"); #include #include @@ -48,6 +50,7 @@ #include "hostfile.h" #include "log.h" #include "xmalloc.h" +#include "ssh-x509.h" static int extract_salt(const char *s, u_int l, char *salt, size_t salt_len) @@ -332,7 +335,17 @@ } fprintf(f, "%s ", store_hash ? hashed_host : host); - if (key_write(key, f)) { +#ifndef SSH_X509STORE_DISABLED + if ((key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA)) { + /* key_write will print x509 certificate in blob format :-( */ + success = x509key_write_subject(key, f); + } else { +#endif /*ndef SSH_X509STORE_DISABLED*/ + success = key_write(key, f); +#ifndef SSH_X509STORE_DISABLED + } +#endif /*ndef SSH_X509STORE_DISABLED*/ + if (success) { success = 1; } else { error("add_host_to_hostfile: saving key in %s failed", filename); diff -ruN openssh-4.2p1/INSTALL openssh-4.2p1+x509-5.5/INSTALL --- openssh-4.2p1/INSTALL 2005-04-24 10:52:23.000000000 +0300 +++ openssh-4.2p1+x509-5.5/INSTALL 2005-09-02 09:06:00.000000000 +0300 @@ -64,6 +64,9 @@ http://www.thrysoee.dk/editline/ http://sourceforge.net/projects/libedit/ +X.509 certificate support: +http://roumenpetrov.info/openssh + 2. Building / Installation -------------------------- @@ -172,6 +175,15 @@ --with-sectok=DIR allows for OpenSC or sectok smartcard libraries to be used with OpenSSH. See 'README.smartcard' for more details. +--with-sshca-dir=PATH allows you to specify location of ssh CA root +used by ssh "x509 store" to verify certificates. + +--disable-x509store allows you to disable ssh "x509 store". In that +case ssh don't verify certificates. Format "Distinguished Name" for a +certificate in ssh files is disabled too. In that case ssh accept only +blob format of certificate in files (aka format of pub files). +See 'README.x509v3' for more details. + If you need to pass special options to the compiler or linker, you can specify these as environment variables before running ./configure. For example: @@ -225,4 +237,4 @@ http://www.openssh.com/ -$Id: INSTALL,v 1.70 2005/04/24 07:52:23 dtucker Exp $ +$Id$ diff -ruN openssh-4.2p1/key.c openssh-4.2p1+x509-5.5/key.c --- openssh-4.2p1/key.c 2005-06-17 05:59:35.000000000 +0300 +++ openssh-4.2p1+x509-5.5/key.c 2006-01-15 09:06:01.000000000 +0200 @@ -10,6 +10,8 @@ * * * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * X.509 certificates support, + * 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,13 +34,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: key.c,v 1.58 2005/06/17 02:44:32 djm Exp $"); +RCSID("$OpenBSD$"); #include #include "xmalloc.h" #include "key.h" #include "rsa.h" +#include "ssh-x509.h" #include "uuencode.h" #include "buffer.h" #include "bufaux.h" @@ -55,9 +58,11 @@ k->flags = 0; k->dsa = NULL; k->rsa = NULL; + k->x509 = NULL; switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_X509_RSA: if ((rsa = RSA_new()) == NULL) fatal("key_new: RSA_new failed"); if ((rsa->n = BN_new()) == NULL) @@ -65,8 +70,13 @@ if ((rsa->e = BN_new()) == NULL) fatal("key_new: BN_new failed"); k->rsa = rsa; + if (k->type == KEY_X509_RSA) { + if ((k->x509 = X509_new()) == NULL) + fatal("key_new: X509_new failed"); + } break; case KEY_DSA: + case KEY_X509_DSA: if ((dsa = DSA_new()) == NULL) fatal("key_new: DSA_new failed"); if ((dsa->p = BN_new()) == NULL) @@ -78,6 +88,10 @@ if ((dsa->pub_key = BN_new()) == NULL) fatal("key_new: BN_new failed"); k->dsa = dsa; + if (k->type == KEY_X509_DSA) { + if ((k->x509 = X509_new()) == NULL) + fatal("key_new: X509_new failed"); + } break; case KEY_UNSPEC: break; @@ -95,6 +109,7 @@ switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_X509_RSA: if ((k->rsa->d = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); if ((k->rsa->iqmp = BN_new()) == NULL) @@ -107,10 +122,25 @@ fatal("key_new_private: BN_new failed"); if ((k->rsa->dmp1 = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); + if (k->type == KEY_X509_RSA) { + debug3("key_new_private: X509(rsa) MORE ...?"); + /* + if ((k->x509 = X509_new()) == NULL) + fatal("key_new: X509_new failed"); + */ + } break; case KEY_DSA: + case KEY_X509_DSA: if ((k->dsa->priv_key = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); + if (k->type == KEY_X509_DSA) { + debug3("key_new_private: X509(dsa) MORE ...?"); + /* + if ((k->x509 = X509_new()) == NULL) + fatal("key_new: X509_new failed"); + */ + } break; case KEY_UNSPEC: break; @@ -135,6 +165,21 @@ DSA_free(k->dsa); k->dsa = NULL; break; + case KEY_X509_RSA: + case KEY_X509_DSA: + if (k->dsa != NULL) { + DSA_free(k->dsa); + k->dsa = NULL; + } + if (k->rsa != NULL) { + RSA_free(k->rsa); + k->rsa = NULL; + } + if (k->x509 != NULL) { + X509_free(k->x509); + k->x509 = NULL; + } + break; case KEY_UNSPEC: break; default: @@ -152,17 +197,29 @@ switch (a->type) { case KEY_RSA1: case KEY_RSA: +#ifdef SSH_X509STORE_DISABLED + case KEY_X509_RSA: +#endif return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; break; case KEY_DSA: +#ifdef SSH_X509STORE_DISABLED + case KEY_X509_DSA: +#endif return a->dsa != NULL && b->dsa != NULL && BN_cmp(a->dsa->p, b->dsa->p) == 0 && BN_cmp(a->dsa->q, b->dsa->q) == 0 && BN_cmp(a->dsa->g, b->dsa->g) == 0 && BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; break; +#ifndef SSH_X509STORE_DISABLED + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_equal(a, b) == 0; + break; +#endif /*ndef SSH_X509STORE_DISABLED*/ default: fatal("key_equal: bad key type %d", a->type); break; @@ -205,6 +262,8 @@ break; case KEY_DSA: case KEY_RSA: + case KEY_X509_RSA: + case KEY_X509_DSA: key_to_blob(k, &blob, &len); break; case KEY_UNSPEC: @@ -410,6 +469,8 @@ case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: + case KEY_X509_RSA: + case KEY_X509_DSA: space = strchr(cp, ' '); if (space == NULL) { debug3("key_read: missing whitespace"); @@ -434,6 +495,11 @@ debug3("key_read: type mismatch"); return -1; } +#ifndef SSH_X509STORE_DISABLED + k = x509key_from_subject(type, cp); + if(k != NULL) + goto noblob; +#endif /*ndef SSH_X509STORE_DISABLED*/ len = 2*strlen(cp); blob = xmalloc(len); n = uudecode(cp, blob, len); @@ -453,7 +519,30 @@ key_free(k); return -1; } +noblob: /*XXXX*/ + if (ret->type == KEY_X509_RSA || + ret->type == KEY_X509_DSA ) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + if (ret->x509 != NULL) + X509_free(ret->x509); + ret->x509 = k->x509; + k->x509 = NULL; +#ifdef DEBUG_PK + if (ret->type == KEY_X509_RSA) + RSA_print_fp(stderr, ret->rsa, 8); + else + DSA_print_fp(stderr, ret->dsa, 8); +#endif + success = 1; + } else if (ret->type == KEY_RSA) { if (ret->rsa != NULL) RSA_free(ret->rsa); @@ -520,6 +609,8 @@ } xfree(blob); xfree(uu); + } else if ( (key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA) ) { + success = x509key_write(key, f); } return success; } @@ -537,6 +628,14 @@ case KEY_DSA: return "DSA"; break; + case KEY_X509_RSA: + if(k->rsa) return "RSA+cert"; + return "X509(rsa)"; + break; + case KEY_X509_DSA: + if(k->dsa) return "DSA+cert"; + return "X509(dsa)"; + break; } return "unknown"; } @@ -544,6 +643,11 @@ const char * key_ssh_name(const Key *k) { + const char* p; + + p = ssh_x509key_name(k); + if (p) return(p); + switch (k->type) { case KEY_RSA: return "ssh-rsa"; @@ -566,6 +670,10 @@ case KEY_DSA: return BN_num_bits(k->dsa->p); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_key_size(k); + break; } return 0; } @@ -640,6 +748,11 @@ int key_type_from_name(char *name) { + int k; + + k = ssh_x509key_type(name); + if (k != KEY_UNSPEC) return(k); + if (strcmp(name, "rsa1") == 0) { return KEY_RSA1; } else if (strcmp(name, "rsa") == 0) { @@ -684,10 +797,14 @@ int rlen, type; char *ktype = NULL; Key *key = NULL; + debug3("key_from_blob(..., %d)", blen); #ifdef DEBUG_PK dump_base64(stderr, blob, blen); #endif + if ((key = x509key_from_blob(blob, blen)) != NULL) { + return key; + } buffer_init(&b); buffer_append(&b, blob, blen); if ((ktype = buffer_get_string_ret(&b, NULL)) == NULL) { @@ -696,6 +813,7 @@ } type = key_type_from_name(ktype); + debug3("key_from_blob(..., ...) ktype=%.30s", ktype); switch (type) { case KEY_RSA: @@ -767,6 +885,11 @@ buffer_put_bignum2(&b, key->rsa->e); buffer_put_bignum2(&b, key->rsa->n); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + if (!x509key_to_blob(key, &b)) + return 0; + break; default: error("key_to_blob: unsupported key type %d", key->type); buffer_free(&b); @@ -797,6 +920,10 @@ case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_sign(key, sigp, lenp, data, datalen); + break; default: error("key_sign: invalid key type %d", key->type); return -1; @@ -824,6 +951,10 @@ case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_verify(key, signature, signaturelen, data, datalen); + break; default: error("key_verify: invalid key type %d", key->type); return -1; @@ -846,6 +977,7 @@ switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_X509_RSA: if ((pk->rsa = RSA_new()) == NULL) fatal("key_demote: RSA_new failed"); if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) @@ -854,6 +986,7 @@ fatal("key_demote: BN_dup failed"); break; case KEY_DSA: + case KEY_X509_DSA: if ((pk->dsa = DSA_new()) == NULL) fatal("key_demote: DSA_new failed"); if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) @@ -866,9 +999,19 @@ fatal("key_demote: BN_dup failed"); break; default: - fatal("key_free: bad key type %d", k->type); + fatal("key_demote: bad key type %d", k->type); break; } + switch (k->type) { + case KEY_X509_RSA: + case KEY_X509_DSA: + if(k->x509) { + if ((pk->x509 = X509_dup(k->x509)) == NULL) + fatal("key_demote: X509_dup failed"); + } else + fatal("key_demote: no X509 data"); + break; + } return (pk); } diff -ruN openssh-4.2p1/key.h openssh-4.2p1+x509-5.5/key.h --- openssh-4.2p1/key.h 2003-11-17 12:18:23.000000000 +0200 +++ openssh-4.2p1+x509-5.5/key.h 2005-09-02 09:06:00.000000000 +0300 @@ -1,7 +1,9 @@ -/* $OpenBSD: key.h,v 1.23 2003/11/10 16:23:41 jakob Exp $ */ +/* $OpenBSD$ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * X.509 certificates support, + * Copyright (c) 2002 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,12 +30,15 @@ #include #include +#include typedef struct Key Key; enum types { KEY_RSA1, KEY_RSA, KEY_DSA, + KEY_X509_RSA, + KEY_X509_DSA, KEY_UNSPEC }; enum fp_type { @@ -53,6 +58,7 @@ int flags; RSA *rsa; DSA *dsa; + X509 *x509; }; Key *key_new(int); diff -ruN openssh-4.2p1/LICENCE openssh-4.2p1+x509-5.5/LICENCE --- openssh-4.2p1/LICENCE 2005-08-26 23:15:20.000000000 +0300 +++ openssh-4.2p1+x509-5.5/LICENCE 2005-09-02 09:06:00.000000000 +0300 @@ -181,6 +181,7 @@ Per Allansson Nils Nordman Simon Wilkinson + Roumen Petrov Portable OpenSSH additionally includes code from the following copyright holders, also under the 2-term BSD license: @@ -332,4 +333,4 @@ ------ -$OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $ +$OpenBSD$ diff -ruN openssh-4.2p1/log.c openssh-4.2p1+x509-5.5/log.c --- openssh-4.2p1/log.c 2005-03-09 11:12:48.000000000 +0200 +++ openssh-4.2p1+x509-5.5/log.c 2005-09-02 09:06:01.000000000 +0300 @@ -34,7 +34,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: log.c,v 1.29 2003/09/23 20:17:11 markus Exp $"); +RCSID("$OpenBSD$"); #include "log.h" #include "xmalloc.h" @@ -280,6 +280,11 @@ #endif } +LogLevel +get_log_level(void) { + return log_level; +} + #define MSGBUFSIZ 1024 void diff -ruN openssh-4.2p1/log.h openssh-4.2p1+x509-5.5/log.h --- openssh-4.2p1/log.h 2004-06-22 05:57:44.000000000 +0300 +++ openssh-4.2p1+x509-5.5/log.h 2005-09-02 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -/* $OpenBSD: log.h,v 1.11 2004/06/21 22:02:58 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -49,6 +49,7 @@ } LogLevel; void log_init(char *, LogLevel, SyslogFacility, int); +LogLevel get_log_level(void); SyslogFacility log_facility_number(char *); LogLevel log_level_number(char *); diff -ruN openssh-4.2p1/m4/ldap.m4 openssh-4.2p1+x509-5.5/m4/ldap.m4 --- openssh-4.2p1/m4/ldap.m4 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/m4/ldap.m4 2005-07-19 23:11:01.000000000 +0300 @@ -0,0 +1,194 @@ +# Options to build with LDAP +# +# Author: Roumen Petrov +# Revision: 19 Jul 2005 +# +dnl The variables provided are : +dnl - build flags: +dnl LDAP_LDFLAGS +dnl LDAP_LIBS +dnl LDAP_CPPFLAGS +dnl - conditional: +dnl LDAP_ON (e.g. '' or '#') +dnl LDAP_OFF (e.g. '#' or '' - oposite of LDAP_ON) +dnl - paths: +dnl LDAP_BINDIR +dnl LDAP_LIBEXECDIR +dnl LDAP_SYSCONFDIR + +AC_DEFUN(AC_WITH_LDAP, +[ +dnl +dnl Get the ldap paths +dnl + +ac_ldap='none' +AC_ARG_ENABLE(ldap, + [ --enable-ldap Enable LDAP queries], + ac_ldap="$enableval" +) + +if test "x$ac_ldap" = xyes; then + ac_ldap_prefix="" + AC_ARG_WITH(ldap-prefix, + [ --with-ldap-prefix=PATH Prefix where LDAP is installed (optional)], + ac_ldap_prefix="$withval" + ) + + AC_ARG_WITH(ldap-bindir, + [ --with-ldap-bindir=PATH Prefix where LDAP user executables are installed (optional)], + [LDAP_BINDIR="$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_BINDIR="$ac_ldap_prefix/bin" + fi + ] + ) + AC_SUBST(LDAP_BINDIR) + + AC_ARG_WITH(ldap-libexecdir, + [ --with-ldap-libexecdir=PATH Prefix where LDAP program executables are installed (optional)], + [LDAP_LIBEXECDIR="$withval"], + [ + if test "x$ac_ldap_prefix" = "x"; then + LDAP_LIBEXECDIR="/usr/libexec" + else + LDAP_LIBEXECDIR="$ac_ldap_prefix/libexec" + fi + ] + ) + AC_SUBST(LDAP_LIBEXECDIR) +dnl### Check for slapd +dnl if test "x$cross_compiling" = "xyes" ; then +dnl AC_MSG_NOTICE([cannot check for LDAP daemon when cross compiling]) +dnl else +dnl AC_CHECK_FILES( +dnl [ +dnl $LDAP_LIBEXECDIR/slapd +dnl ] +dnl ) +dnl fi + + AC_ARG_WITH(ldap-sysconfdir, + [ --with-ldap-sysconfdir=PATH Prefix where LDAP single-machine data are installed (optional)], + [LDAP_SYSCONFDIR="$withval"], + [LDAP_SYSCONFDIR="$ac_ldap_prefix/etc/openldap"] + ) + AC_SUBST(LDAP_SYSCONFDIR) +dnl### Check for schema files +dnl if test "x$cross_compiling" = "xyes" ; then +dnl AC_MSG_NOTICE([cannot check for schema files existence when cross compiling]) +dnl else +dnl AC_CHECK_FILES( +dnl [ +dnl $LDAP_SYSCONFDIR/schema/core.schema +dnl $LDAP_SYSCONFDIR/schema/cosine.schema +dnl $LDAP_SYSCONFDIR/schema/inetorgperson.schema +dnl ] +dnl ) +dnl fi + + + AC_ARG_WITH(ldap-libdir, + [ --with-ldap-libdir=PATH Prefix where LDAP libaries are installed (optional)], + [LDAP_LDFLAGS="-L$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_LDFLAGS="-L$ac_ldap_prefix/lib" + else + LDAP_LDFLAGS="" + fi + ] + ) + AC_SUBST(LDAP_LDFLAGS) + + AC_ARG_WITH(ldap-includedir, + [ --with-ldap-includedir=PATH Prefix where LDAP header files are installed (optional)], + [LDAP_CPPFLAGS="-I$withval"], + [ + if test "x$ac_ldap_prefix" != "x"; then + LDAP_CPPFLAGS="-I$ac_ldap_prefix/include" + else + LDAP_CPPFLAGS="" + fi + ] + ) + AC_SUBST(LDAP_CPPFLAGS) + + + ac_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + AC_CHECK_HEADERS( + [lber.h ldap.h], + [], + [ + AC_MSG_ERROR([cannot found LDAP headers]) + ] + ) + CPPFLAGS="$ac_save_CPPFLAGS" + + ac_ldap_libs="" + AC_ARG_WITH(ldap-libs, + [ --with-ldap-libs=LIBS Specify LDAP libraries to link with. + (default is -lldap -llber -lssl -lcrypto)], + [ac_ldap_libs="$withval"] + ) + +### Try to link with LDAP libs + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + + LDFLAGS="$LDAP_LDFLAGS $LDFLAGS" + ac_LDAP_LINK="" + if test "x$ac_ldap_libs" != "x"; then + AC_MSG_CHECKING([to link with specified LDAP libs]) + + LDAP_LIBS="$ac_ldap_libs" + LIBS="$LDAP_LIBS $ac_save_LIBS" + AC_LINK_IFELSE( + [AC_LANG_CALL([], [ldap_init])], + [ac_LDAP_LINK="yes"] + ) + if test "x$ac_LDAP_LINK" != "xyes"; then + AC_MSG_ERROR([cannot link with specified LDAP libs]) + fi + else + AC_MSG_CHECKING([how to link LDAP libs]) + + LDAP_LIBS="-lldap" + for L in lber ssl crypto; do + LDAP_LIBS="$LDAP_LIBS -l$L" + LIBS="$LDAP_LIBS $ac_save_LIBS" + AC_LINK_IFELSE( + [AC_LANG_CALL([], [ldap_init])], + [ac_LDAP_LINK="yes"] + ) + if test "x$ac_LDAP_LINK" = "xyes"; then + break + fi + done + if test "x$ac_LDAP_LINK" != "xyes"; then + AC_MSG_ERROR([cannot link with default LDAP libs]) + fi + fi + AC_MSG_RESULT([done]) + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + AC_SUBST([LDAP_LIBS]) +else + AC_MSG_NOTICE([LDAP is disabled]) +fi + +if test "x$ac_ldap" = "xyes"; then + AC_DEFINE_UNQUOTED( + LDAP_ENABLED, 1, + [Define if you want to enable LDAP queries]) + LDAP_ON='' + LDAP_OFF='#' +else + LDAP_ON='#' + LDAP_OFF='' +fi +AC_SUBST(LDAP_ON) +AC_SUBST(LDAP_OFF) +]) diff -ruN openssh-4.2p1/Makefile.in openssh-4.2p1+x509-5.5/Makefile.in --- openssh-4.2p1/Makefile.in 2005-05-29 10:22:29.000000000 +0300 +++ openssh-4.2p1+x509-5.5/Makefile.in 2006-04-26 09:06:01.000000000 +0300 @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.273 2005/05/29 07:22:29 dtucker Exp $ +# $Id$ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -14,6 +14,7 @@ mandir=@mandir@ mansubdir=@mansubdir@ sysconfdir=@sysconfdir@ +sshcadir=@sshcadir@ piddir=@piddir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ @@ -30,6 +31,7 @@ STRIP_OPT=@STRIP_OPT@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \ + -DSSHCADIR=\"$(sshcadir)\" \ -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \ @@ -41,11 +43,12 @@ CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ -CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ +CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ @LDAP_CPPFLAGS@ $(PATHS) @DEFS@ LIBS=@LIBS@ LIBEDIT=@LIBEDIT@ LIBPAM=@LIBPAM@ LIBWRAP=@LIBWRAP@ +LIBLDAP=@LDAP_LDFLAGS@ @LDAP_LIBS@ AR=@AR@ AWK=@AWK@ RANLIB=@RANLIB@ @@ -60,6 +63,15 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ +@LDAP_ON@LDAP_OBJS=x509_by_ldap.o +@LDAP_OFF@LDAP_OBJS= + +@OCSP_ON@OCSP_OBJS=ssh-ocsp.o +@OCSP_OFF@OCSP_OBJS= + +SSHX509_OBJS=ssh-x509.o ssh-xkalg.o x509_nm_cmp.o +X509STORE_OBJS=x509store.o $(LDAP_OBJS) $(OCSP_OBJS) + TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o buffer.o \ @@ -69,12 +81,12 @@ log.o match.o moduli.o nchan.o packet.o \ readpass.o rsa.o ttymodes.o xmalloc.o \ atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o $(SSHX509_OBJS) dh.o kexdh.o \ kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ entropy.o scard-opensc.o gss-genr.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o + sshconnect.o sshconnect1.o sshconnect2.o $(X509STORE_OBJS) SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ sshpty.o sshlogin.o servconf.o serverloop.o \ @@ -86,7 +98,7 @@ auth-krb5.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - audit.o audit-bsm.o + audit.o audit-bsm.o $(X509STORE_OBJS) MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5 @@ -105,6 +117,10 @@ -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \ -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \ -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \ + -e 's|/etc/ssh/ca/ca-bundle.crt|$(sshcadir)/ca-bundle.crt|g' \ + -e 's|/etc/ssh/ca/crt|$(sshcadir)/crt|g' \ + -e 's|/etc/ssh/ca/ca-bundle.crl|$(sshcadir)/ca-bundle.crl|g' \ + -e 's|/etc/ssh/ca/crl|$(sshcadir)/crl|g' \ -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \ -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \ -e 's|/etc/sshrc|$(sysconfdir)/sshrc|g' \ @@ -133,10 +149,10 @@ $(RANLIB) $@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) - $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBLDAP) $(LIBS) sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) - $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBWRAP) $(LIBPAM) $(LIBS) + $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBWRAP) $(LIBPAM) $(LIBLDAP) $(LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o $(LD) -o $@ scp.o progressmeter.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) @@ -150,8 +166,8 @@ ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o - $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o $(X509STORE_OBJS) + $(LD) -o $@ ssh-keysign.o readconf.o $(X509STORE_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBLDAP) $(LIBS) ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) @@ -206,6 +222,7 @@ rm -rf autom4te.cache (cd openbsd-compat && $(MAKE) distclean) (cd scard && $(MAKE) distclean) + (cd tests/CA && $(MAKE) distclean) if test -d pkg ; then \ rm -fr pkg ; \ fi @@ -249,6 +266,8 @@ $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)5 $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)8 $(srcdir)/mkinstalldirs $(DESTDIR)$(libexecdir) + $(srcdir)/mkinstalldirs $(DESTDIR)$(sshcadir) + $(srcdir)/mkinstalldirs $(DESTDIR)$(piddir) (umask 022 ; $(srcdir)/mkinstalldirs $(DESTDIR)$(PRIVSEP_PATH)) $(INSTALL) -m 0755 $(STRIP_OPT) ssh $(DESTDIR)$(bindir)/ssh $(INSTALL) -m 0755 $(STRIP_OPT) scp $(DESTDIR)$(bindir)/scp @@ -377,7 +396,14 @@ -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 -tests: $(TARGETS) + +tests: check + +# Target check is more common for the projects using autoXXXX tools + +check: check-regress check-certs + +check-regress: $(TARGETS) BUILDDIR=`pwd`; \ [ -d `pwd`/regress ] || mkdir -p `pwd`/regress; \ [ -f `pwd`/regress/Makefile ] || \ @@ -408,12 +434,29 @@ TEST_SSH_SFTP="$${TEST_SSH_SFTP}" \ TEST_SSH_SFTPSERVER="$${TEST_SSH_SFTPSERVER}" \ EXEEXT="$(EXEEXT)" \ - $@ + tests + + +check-certs: $(TARGETS) + @BUILDDIR="`pwd`"; \ + ( cd "tests/CA" && \ + $(MAKE) \ + TEST_SSH_SSH="$${BUILDDIR}/ssh" \ + TEST_SSH_SSHD="$${BUILDDIR}/sshd" \ + TEST_SSH_SSHAGENT="$${BUILDDIR}/ssh-agent" \ + TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add" \ + TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen" \ + TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan" \ + TEST_SSH_SFTP="$${BUILDDIR}/sftp" \ + TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server" \ + $@ ) + regressclean: if [ -f regress/Makefile ] && [ -r regress/Makefile ]; then \ (cd regress && $(MAKE) clean) \ fi + (cd tests/CA && $(MAKE) clean) survey: survey.sh ssh @$(SHELL) ./survey.sh > survey diff -ruN openssh-4.2p1/myproposal.h openssh-4.2p1+x509-5.5/myproposal.h --- openssh-4.2p1/myproposal.h 2005-07-26 14:54:56.000000000 +0300 +++ openssh-4.2p1+x509-5.5/myproposal.h 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.18 2005/07/25 11:59:39 markus Exp $ */ +/* $OpenBSD: myproposal.h,v 1.16 2004/06/13 12:53:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. diff -ruN openssh-4.2p1/pathnames.h openssh-4.2p1+x509-5.5/pathnames.h --- openssh-4.2p1/pathnames.h 2004-07-17 09:12:08.000000000 +0300 +++ openssh-4.2p1+x509-5.5/pathnames.h 2005-09-02 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.15 2004/07/11 17:48:47 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -10,6 +10,29 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X.509 certificates support, + * Copyright (c) 2002 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. */ #define ETCDIR "/etc" @@ -172,3 +195,20 @@ #ifndef ASKPASS_PROGRAM #define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass" #endif /* ASKPASS_PROGRAM */ + + +#ifndef SSHCADIR +#define SSHCADIR SSHDIR "/ca" +#endif + +/* x509 user store */ +#define _PATH_USERCA_CERTIFICATE_FILE "~/" _PATH_SSH_USER_DIR "/ca-bundle.crt" +#define _PATH_USERCA_CERTIFICATE_PATH "~/" _PATH_SSH_USER_DIR "/crt" +#define _PATH_USERCA_REVOCATION_FILE "~/" _PATH_SSH_USER_DIR "/ca-bundle.crl" +#define _PATH_USERCA_REVOCATION_PATH "~/" _PATH_SSH_USER_DIR "/crl" + +/* x509 system store */ +#define _PATH_CA_CERTIFICATE_FILE SSHCADIR "/ca-bundle.crt" +#define _PATH_CA_CERTIFICATE_PATH SSHCADIR "/crt" +#define _PATH_CA_REVOCATION_FILE SSHCADIR "/ca-bundle.crl" +#define _PATH_CA_REVOCATION_PATH SSHCADIR "/crl" diff -ruN openssh-4.2p1/readconf.c openssh-4.2p1+x509-5.5/readconf.c --- openssh-4.2p1/readconf.c 2005-08-12 15:11:18.000000000 +0300 +++ openssh-4.2p1+x509-5.5/readconf.c 2006-04-26 09:06:01.000000000 +0300 @@ -9,10 +9,33 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X509 certificate support, + * Copyright (c) 2002-2006 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" -RCSID("$OpenBSD: readconf.c,v 1.143 2005/07/30 02:03:47 djm Exp $"); +RCSID("$OpenBSD$"); #include "ssh.h" #include "xmalloc.h" @@ -24,6 +47,8 @@ #include "match.h" #include "misc.h" #include "kex.h" +#include "myproposal.h" +#include "ssh-xkalg.h" #include "mac.h" /* Format of the configuration file: @@ -107,6 +132,18 @@ oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, + oPubkeyAlgorithms, + oX509KeyAlgorithm, + oAllowedServerCertPurpose, + oMandatoryCRL, + oCACertificateFile, oCACertificatePath, + oCARevocationFile, oCARevocationPath, + oCAldapVersion, oCAldapURL, + oUserCACertificateFile, oUserCACertificatePath, + oUserCARevocationFile, oUserCARevocationPath, + oUserCAldapVersion, oUserCAldapURL, + oVAType, oVACertificateFile, + oVAOCSPResponderURL, oDeprecated, oUnsupported } OpCodes; @@ -198,6 +235,26 @@ { "controlpath", oControlPath }, { "controlmaster", oControlMaster }, { "hashknownhosts", oHashKnownHosts }, + { "pubkeyalgorithms", oPubkeyAlgorithms }, + { "x509rsasigtype", oDeprecated }, + { "x509keyalgorithm", oX509KeyAlgorithm }, + { "allowedcertpurpose", oAllowedServerCertPurpose }, + { "mandatorycrl", oMandatoryCRL }, + { "cacertificatefile", oCACertificateFile }, + { "cacertificatepath", oCACertificatePath }, + { "carevocationfile", oCARevocationFile }, + { "carevocationpath", oCARevocationPath }, + { "caldapversion", oCAldapVersion }, + { "caldapurl", oCAldapURL }, + { "usercacertificatefile", oUserCACertificateFile }, + { "usercacertificatepath", oUserCACertificatePath }, + { "usercarevocationfile", oUserCARevocationFile }, + { "usercarevocationpath", oUserCARevocationPath }, + { "usercaldapversion", oCAldapVersion }, + { "usercaldapurl", oCAldapURL }, + { "vatype", oVAType }, + { "vacertificatefile", oVACertificateFile }, + { "vaocspresponderurl", oVAOCSPResponderURL }, { NULL, oBadOption } }; @@ -621,9 +678,11 @@ arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); + /* cannot validate here - depend from X509KeyAlgorithm if (!key_names_valid2(arg)) fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", filename, linenum, arg ? arg : ""); + */ if (*activep && options->hostkeyalgorithms == NULL) options->hostkeyalgorithms = xstrdup(arg); break; @@ -822,11 +881,180 @@ intptr = &options->hash_known_hosts; goto parse_flag; + case oPubkeyAlgorithms: + charptr = (char**)&options->pubkey_algorithms; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + /* cannot validate here - depend from X509KeyAlgorithm + if (!key_names_valid2(arg)) + fatal("%.200s line %d: Bad protocol 2 public key algorithms '%s'.", + filename, linenum, arg ? arg : ""); + */ + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; + + case oX509KeyAlgorithm: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + + if (*activep) { + if (ssh_add_x509key_alg(arg) < 0) { + fatal("%.200s line %d: Bad X.509 key algorithm '%.200s'.", + filename, linenum, arg); + } + } + break; + + case oAllowedServerCertPurpose: + intptr = &options->x509flags->allowedcertpurpose; + arg = strdelim(&s); + if (arg && *arg) { + if (strcasecmp(arg, "skip") == 0) goto skip_purpose; + + /* convert string to OpenSSL index */ + value = ssh_get_x509purpose_s (0, arg); + if (value < 0) + fatal("%.200s line %d: Bad certificate purpose '%.30s'.", + filename, linenum, arg); + + if (*activep && *intptr == -1) + *intptr = value; + } else { +skip_purpose: + if (*activep && *intptr == -1) { + *intptr = -2; + verbose("%.200s line %d: option is set to don`t check certificate purpose.", + filename, linenum); + } + } + break; + +#ifndef SSH_X509STORE_DISABLED + case oMandatoryCRL: + intptr = &options->x509flags->mandatory_crl; + goto parse_flag; + + case oCACertificateFile: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.certificate_file; + goto parse_string; + + case oCACertificatePath: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.certificate_path; + goto parse_string; + + case oCARevocationFile: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.revocation_file; + goto parse_string; + + case oCARevocationPath: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.revocation_path; + goto parse_string; + + case oUserCACertificateFile: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.certificate_file; + goto parse_string; + + case oUserCACertificatePath: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.certificate_path; + goto parse_string; + + case oUserCARevocationFile: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.revocation_file; + goto parse_string; + + case oUserCARevocationPath: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.revocation_path; + goto parse_string; +#endif /*ndef SSH_X509STORE_DISABLED*/ + +#ifdef LDAP_ENABLED + case oCAldapVersion: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.ldap_ver; + goto parse_string; + + case oCAldapURL: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.ldap_url; + goto parse_string; + + case oUserCAldapVersion: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.ldap_ver; + goto parse_string; + + case oUserCAldapURL: + /*X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->userca.ldap_url; + goto parse_string; +#endif /*def LDAP_ENABLED*/ + +#ifdef SSH_OCSP_ENABLED + case oVAType: + intptr = &options->va.type; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + + value = ssh_get_vatype_s(arg); + if (value < 0) { + fatal("%.200s line %d: Bad OCSP responder type '%.30s'.", + filename, linenum, arg); + } + + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oVACertificateFile: + /* VAOptions prefered type is 'const char*' */ + charptr = (char**)&options->va.certificate_file; + goto parse_string; + + case oVAOCSPResponderURL: + /* VAOptions prefered type is 'const char*' */ + charptr = (char**)&options->va.responder_url; + goto parse_string; +#endif /*def SSH_OCSP_ENABLED*/ + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); return 0; +#ifdef SSH_X509STORE_DISABLED + case oMandatoryCRL: + case oCACertificateFile: + case oCACertificatePath: + case oCARevocationFile: + case oCARevocationPath: + case oUserCACertificateFile: + case oUserCACertificatePath: + case oUserCARevocationFile: + case oUserCARevocationPath: +#endif /*def SSH_X509STORE_DISABLED*/ +#ifndef LDAP_ENABLED + case oCAldapVersion: + case oCAldapURL: + case oUserCAldapVersion: + case oUserCAldapURL: +#endif /*ndef LDAP_ENABLED*/ +#ifndef SSH_OCSP_ENABLED + case oVAType: + case oVACertificateFile: + case oVAOCSPResponderURL: +#endif /*ndef SSH_OCSP_ENABLED*/ case oUnsupported: error("%s line %d: Unsupported option \"%s\"", filename, linenum, keyword); @@ -966,7 +1194,37 @@ options->control_path = NULL; options->control_master = -1; options->hash_known_hosts = -1; + options->pubkey_algorithms = NULL; + /* Supported X.509 key algorithms and signatures + are defined is external source. */ + options->x509flags = &ssh_x509flags; + ssh_x509flags_initialize(options->x509flags, 0); +#ifndef SSH_X509STORE_DISABLED + ssh_x509store_initialize(&options->ca); + ssh_x509store_initialize(&options->userca); +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + options->va.type = -1; + options->va.certificate_file = NULL; + options->va.responder_url = NULL; +#endif /*def SSH_OCSP_ENABLED*/ +} + +#ifndef SSH_X509STORE_DISABLED +static int +ssh_x509store_init (Options *options) { + int x509_store_loaded = 0; + + if(ssh_x509store_addlocations(&options->userca)) { + x509_store_loaded = 1; + } + if(ssh_x509store_addlocations(&options->ca)) { + x509_store_loaded = 1; + } + + return x509_store_loaded; } +#endif /*ndef SSH_X509STORE_DISABLED*/ /* * Called after processing other sources of option data, this fills those @@ -1033,7 +1291,7 @@ options->cipher = SSH_CIPHER_NOT_SET; /* options->ciphers, default set in myproposals.h */ /* options->macs, default set in myproposals.h */ - /* options->hostkeyalgorithms, default set in myproposals.h */ + /* HostKeyAlgorithms depend from X509KeyAlgorithm options */ if (options->protocol == SSH_PROTO_UNKNOWN) options->protocol = SSH_PROTO_1|SSH_PROTO_2; if (options->num_identity_files == 0) { @@ -1095,6 +1353,58 @@ /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ + + /* options->pubkey_algorithms */ + fill_default_xkalg(); + ssh_x509flags_defaults(options->x509flags); +#ifndef SSH_X509STORE_DISABLED + ssh_x509store_system_defaults(&options->ca); + + { + extern uid_t original_real_uid; + ssh_x509store_user_defaults(&options->userca, original_real_uid); + } + + ssh_x509store_init(options); +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + if (options->va.type == -1) + options->va.type = ssh_get_default_vatype(); + ssh_set_validator(&options->va); +#endif /*def SSH_OCSP_ENABLED*/ + + if (options->hostkeyalgorithms != NULL) { + if (!key_names_valid2(options->hostkeyalgorithms)) + fatal("Bad protocol 2 host key algorithms '%s'.", + options->hostkeyalgorithms); + } else { + Buffer b; + + buffer_init(&b); + ssh_list_xkalg(KEY_X509_RSA, &b); + ssh_list_xkalg(KEY_X509_DSA, &b); + if (buffer_len(&b) > 0) { + /* use defined X.509 "key type name" plus default set in myproposals.h */ + const char *p = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; + + buffer_append(&b, ",", 1); + buffer_append(&b, p, strlen(p)); + buffer_append(&b, "\0", 1); + + options->hostkeyalgorithms = xstrdup(buffer_ptr(&b)); + } else { + /* use default set in myproposals.h */ + } +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG hostkeyalgorithms='%s'\n", (options->hostkeyalgorithms ? options->hostkeyalgorithms : "")); +#endif + buffer_free(&b); + } + + if (options->pubkey_algorithms != NULL) + if (!key_names_valid2(options->pubkey_algorithms)) + fatal("Bad protocol 2 public key algorithms '%s'.", + options->pubkey_algorithms); } /* diff -ruN openssh-4.2p1/readconf.h openssh-4.2p1+x509-5.5/readconf.h --- openssh-4.2p1/readconf.h 2005-06-16 06:19:42.000000000 +0300 +++ openssh-4.2p1+x509-5.5/readconf.h 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.67 2005/06/08 11:25:09 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -11,12 +11,36 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X509 certificate support, + * Copyright (c) 2002-2006 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. */ #ifndef READCONF_H #define READCONF_H #include "key.h" +#include "x509store.h" /* Data structure for representing a forwarding request. */ @@ -114,6 +138,24 @@ int control_master; int hash_known_hosts; + + char* pubkey_algorithms; /* Allowed pubkey algorithms. */ + + /* Supported X.509 key algorithms and signatures + are defined is external source. */ + + /* ssh PKI(X509) flags */ + SSH_X509Flags *x509flags; +#ifndef SSH_X509STORE_DISABLED + /* sshd PKI(X509) system store */ + X509StoreOptions ca; + /* sshd PKI(X509) user store */ + X509StoreOptions userca; +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + /* ssh X.509 extra validation */ + VAOptions va; +#endif /*def SSH_OCSP_ENABLED*/ } Options; #define SSHCTL_MASTER_NO 0 diff -ruN openssh-4.2p1/README.x509v3 openssh-4.2p1+x509-5.5/README.x509v3 --- openssh-4.2p1/README.x509v3 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/README.x509v3 2006-04-26 00:16:13.000000000 +0300 @@ -0,0 +1,504 @@ + Roumen Petrov + Sofia, Bulgaria + Wed Apr 12 2006 + +How to use X.509 certificates with OpenSSH? + + +Identity or hostkey file for protocol version 2 can contain private key +plus X.509 certificate in PEM format. Note that protocol version 2 keys +are in PEM format. To use X.509 certificate as identity or hostkey user +should convert certificate in PEM format and append to file. After this +with "ssh-keygen -y ..." user must update "pub" file. +File (identity or hostkey) with X.509 certificate (RSA key): +-----BEGIN RSA PRIVATE KEY----- +..... +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +..... +-----END CERTIFICATE----- +Note that to use X.509 certificates in OpenSSH files must contain +private key followed by certificate that match private key! + + +1.) server configuration: + +1.1.) .../sshd_config + +1.1.1.) AllowedCertPurpose sslclient + The intended use off the X.509 client certificate. + +1.1.2.) "X509 store". + Server use "X509 store" to verify and validate client keys. + +1.1.2.1.) CACertificateFile /etc/ssh/ca/ca-bundle.crt + This file contain multiple certificates of certificate signers in PEM +format concatenated together. You can get a copy from openssl, apache, +KDE, mutt, etc. packages. Original file might is exported from Netscape +certificate database and one download URL is: + http://www.modssl.org/contrib/ca-bundle.crt.tar.gz + +1.1.2.2.) CACertificatePath /etc/ssh/ca/crt + "Hash dir" with certificates of certificate signers. Each certificate +should be stored in separate file with name [HASH].[NUMBER], where +[HASH] is certificate hash value and [NUMBER] is an integer starting +from zero. Hash is result from command like this: +$ openssl x509 -in certificate_file_name -noout -hash + +1.1.2.3.) CARevocationFile /etc/ssh/ca/ca-bundle.crl + This file contain multiple "Certificate Revocation List" (CRL) of +certificate signers in PEM format concatenated together. + +1.1.2.4.) CARevocationPath /etc/ssh/ca/crl + "Hash dir" with "Certificate Revocation List" (CRL) of certificate +signers. Each CRL should be stored in separate file with name +[HASH].r[NUMBER], where [HASH] is CRL hash value and [NUMBER] is an +integer starting from zero. Hash is result from command like this: +$ openssl crl -in crl_file_name -noout -hash + +1.1.2.5.) CAldapVersion + LDAP protocol version. Default depend from LDAP library. + +1.1.2.6.) CAldapURL + Hostport and dn of LDAP URL. No default value. + +1.1.3.) HostKey files... + Host key for protocol version 2 can contain private key plus X.509 +certificate in PEM format. + +1.1.4.) X509KeyAlgorithm + This is new option that replace old one X509rsaSigType. + The option list multiple "X509 Key Algorithms Formats" + supported by server. + The format is described in sshd_config(5). + The default for certificates with RSA key is: + X509KeyAlgorithm x509v3-sign-rsa,rsa-md5 + X509KeyAlgorithm x509v3-sign-rsa,rsa-sha1 + The default for certificates with DSA key is: + X509KeyAlgorithm x509v3-sign-dss,dss-asn1 + X509KeyAlgorithm x509v3-sign-dss,dss-raw + The first listed format for each key-type, i.e. RSA or DSA + is used as default in signing. The server will accept + all listed formats. + +1.1.5.) X509rsaSigType=md5 + Deprecated option replaced by X509KeyAlgorithm. + +1.1.6.) VAType none + Specifies whether `Online Certificate Status Protocol' (OCSP) is used + to validate client X.509 certificates. Specified value is used only + when OpenSSH is build with OCSP support. See sshd_config(5) man page + for allowed values and other VA* options. + +1.1.7.) KeyAllowSelfIssued no + Specifies whether self-issued(self-signed) X.509 certificate can be + allowed only by entry in AutorizedKeysFile that contain matching + public key or certificate blob. + +1.2.) user files on the server + Append in USER_HOME/.ssh/authorized_keys a record with following +format: +{|CertBlob} +where: +KEY_TYPE:=x509v3-sign-rsa|x509v3-sign-dss (case sensitive !) +WORDDN:={Distinguished Name| + Distinguished-Name| + Distinguished_Name| + DistinguishedName| + DN| + Subject} +WORDDNSUFF:='='|':'|'' +NOTES: +- WORDDN is case insensitive ! + +- is like output from command: +$ openssl x509 -noout -subject -in A_CERTIFICATE_FILE + +- can be in RFC2253 format like output from command: +$ openssl x509 -noout -subject -in A_CERTIFICATE_FILE -nameopt RFC2253 + +- Order of items in is not important and separator +can be symbol "/", "," or mixed. All following subjects are equal: +a)CN=dsa test certificate,OU=OpenSSH Testers,O=Test Team,ST=World,C=XX +b)/C=XX/ST=World/O=Test Team/OU=OpenSSH Testers/CN=dsa test certificate +c)/O=Test Team/OU=OpenSSH Testers/C=XX/ST=World/CN=dsa test certificate +d)O=Test Team,OU=OpenSSH Testers/C=XX,ST=World/CN=dsa test certificate + +- CertBlob is uuencoded sequence of bytes in only one line. + +Shell sample: +- "Distinguished Name" format: +$ ( printf 'x509v3-sign-rsa '; + openssl x509 -noout -subject \ + -in A_OPENSSH_IDENTITY_FILE \ + ) >> $HOME/.ssh/authorized_keys + +- "blob" format: +$ cat A_OPENSSH_IDENTITY_FILE.pub \ + >> $HOME/.ssh/authorized_keys + +NOTES: +- adjust user authorized_keys file ownership - user must have at least +read access. +- SecSH X.509 key type is "x509v3-sign-rsa" or "x509v3-sign-dss". +- When OpenSSH is build with "--disable-x509store" YOU CANNOT USE +"Distinguished Name" format. You shold use ONLY "blob" format. + + +2.) client settings: +2.1.) IdentityFile + Depends from client. To use X.509 certificate "OpenSSH id-file" must +contain both sections - private key and certificate in PEM format: +Note: Don't forget to update public key file with command: +$ ssh-keygen -y -f IDENTITY_FILE > IDENTITY_FILE.pub +Command ssh-add use public key file! + +2.2.) global ssh_config, $HOME/.ssh/config or command line + +2.2.1.) AllowedCertPurpose sslserver + The intended use of the X.509 server certificate. + +2.2.2.) "X509 store". + Client use "X509 store" to verify and validate server hostkey. + See p. 1.1.2.) and check the options: +- [User]CACertificatePath; +- [User]CACertificateFile; +- [User]CARevocationFile; +- [User]CARevocationPath; +- [User]CAldapVersion; +- [User]CAldapURL. + +Note: When we use own CA we must import CA certificate[s] to +"X509 store". More info on: + http://roumenpetrov.info/domino_CA/#dca2bundle + +2.2.3.) X509KeyAlgorithm + The meaning of options is same as in server. + See p. 1.1.4.) + +2.2.4.) X509rsaSigType=md5 + Deprecated option replaced by X509KeyAlgorithm. + +2.2.5.) VAType none + Specifies whether `Online Certificate Status Protocol' (OCSP) is used + to validate server X.509 certificates. Specified value is used only + when OpenSSH is build with OCSP support. See ssh_config(5) man page + for allowed values and other VA* options. + + +3.) test X.509 certificates. + +3.1.) In openssh build dir run "make check" or "make test". + Both commands are equivalent and run regression tests. + If you want to test only X.509 certificates you can run +$ make check-certs + + If certificate test scripts fail might you should setup test +configuration in the file OPENSSH_SOURCE_PATH/tests/CA/config or +use some environment variables. Used variables are described +later in the document. + + Output from "make check-certs" is in color and when is redirected to +file later we can see content best with command "less -r ...". + When script run a test command print star '*' followed by simple +information about command. When command succeed script print at right +"done" in GREEN(!) otherwise "failed" in RED(!). After failed command +script show on next lines in RED(!) response, skip execution of next +command/script, print message like this: +.... +Testing OpenSSH client with certificates finished. + status: failed +.... + Note that failed is in RED(!) and exit code is NONZERO(!). + Some command in a test script must fail. Part of "simple information" +about command expected to fail is in RED(!). When command fail script +print "done" (THIS IS CORRECT - COMMAND MUST FAIL) and on next lines +print in GREEN(!) response. Usually this occur when server reject logon. +WHEN ALL TESTS SUCCEED output is: +.... +Testing OpenSSH client with certificates finished. + status: done +.... + Note that "done" is in GREEN(!) and exit code is ZERO(!). + +3.1.1.) Description of variables in Makefile file: + - SHELL + Used shell to run tests. Supported shell are bash, ksh, zsh and ash. + Script might run without porblems on standard unix sh. + Example: + $ make check-certs SHELL=/bin/zsh + +3.1.2.) Description of variables in config file: + +3.1.2.1.) main variables: + - SUDO + (only in config) + on some system sshd must be started as root. + If necessary set variable to sudo and configure sudo'ers. + - TMPDIR + (environment or config) + directory for temporary files. If not set its value is selected + from /tmp, /var/tmp or /usr/tmp. + - SSH_X509TESTS + (environment or config) + list with test scripts. A test script is in file with following + name: test-.sh.inc. + +3.1.2.2.) openssl: + - OPENSSL + (environment or config) + path to openssl binary. The default is result from command: + `which openssl`. + - RSA_DIGEST_LIST + (environment or config) + list with RSA digests in support of openssl. The default value is + build at run time from following digest list "md5 sha1 md2 md4 + rmd160" and contain only supported from openssl. + +3.1.2.3.) server section: + Read sshd_config.5 manual page for valid values. + - SSHD_PORT + (environment or config) + Specifies the port number that server listens on and client connect + to on SSHD_LISTENADDRESS. The default is 20022. + - SSHD_LISTENADDRESS + (only in config) + Same as sshd option "ListenAddress" but without(!) port number. + The default is "127.0.0.1". + - SSHSERVER_USEPRIVILEGESEPARATION="yes": + (only in config) + sshd "UsePrivilegeSeparation" option. + if necessary set to "no", to disable privilege separation. + - SSHSERVER_SYSLOGFACILITY=AUTH + (only in config) + sshd "SyslogFacility" option. + - SSHSERVER_LOGLEVEL=INFO + (only in config) + sshd 'LogLevel' option. + +3.1.2.4.) certificates: + - Variables related to test certificates and CA. + (only in config) + +3.1.2.5.) OCSP responder: + Used only when OpenSSH is build with OCSP support! + Variables related to OCSP tests. + - SSH_VA_BASEPORT + (environment or config) + Test script run one or more OCSP responders at same once. First + responder listen on specified port, second on port plus one and + etc. The default is 20080. + - SSH_OPENSLL_OCSP_TMOUT=60 + (config) + Wait specified number of seconds sockets opened by OCSP responders + to close. After this test script continue with next step. + This is work around for missing SO_REUSEADDR socket option in + OpenSSL OCSP responder. + +3.1.2.5.) LDAP: + In use only when OpenSSH is build with LDAP support! + - SSH_LDAP_DB + (config) + Specifies LDAP database type. The default is ldbm. + - SSH_LDAP_DC + (config) + Specifies domain name component in LDAP distinguished name. + The default is "dc=example,dc=com". + - LDAPD_PORT + (environment or config) + LDAP daemon run by test script run listens on SSHD_LISTENADDRESS + and this port. The default is 20389. + +3.1.3.) Sample commands to run tests: +$ OPENSSL=/usr/local/ssl/bin/openssl make check-certs +$ SSHD_PORT=1122 SSH_X509TESTS="agent blob_auth" make check-certs +$ RSA_DIGEST_LIST="md5 sha1" make check-certs +$ make check-certs SHELL=/bin/ksh + +When check fail see "Troubleshooting" later in document. + + +3.2.) Current test scripts uses only rsa as server hostkey. + To test sshd with X.509 certificate please find in file +openssh_tests.sh variable TEST_SSHD_HOSTKEY and change it. Sample: +TEST_SSH_HOSTKEY="${CWD}/testhostkey_rsa-rsa_md5" + + +3.3.) Test SecSH from "Microsoft Windows OS-es". + This is not part of document. +Tips: use created after "make check-certs" files: +- convert OPENSSH_BUILD_PATH/tests/CA/ca-test/crt/*crt.pem CA + certificates from PEM to DER format and import in + "Windows keystore"; +- import OPENSSH_BUILD_PATH/tests/CA/testid_*.p12 files in + "Windows keystore"; +- setup your client to use certificate[s](see SecSH client manuals). +DON'T FORGET TO REMOVE entries from "Windows keystore" after test! + + +3.4.) Go to OPENSSH_BUILD_PATH/tests/CA and run command "make clean" to +remove all client/server and CA files. + + +3.5.) files in OPENSSH_SOURCE_PATH/tests/CA directory: +config: + Configuration file. + +env.in: + Template file. + Currently contain variables related to LDAP directories. + +shell.rc: + Shell settings. + +1-cre_cadb.sh: + Create "Test CA" directories and files. + +2-cre_cakeys.sh: + Create "Test CA" private keys and certificates. + +3-cre_certs.sh: + Create client/server certificates. + This command create files with mask + "PATH_TO_KEYFILEn-[.]" + , where is in format "rsa_" or "dsa". + DIGEST are form variable "RSA_DIGEST_LIST" specified in "config" + file. Files without extention are openssh identity or hostkey files. + File with .pub extention contain openssh public key (BLOB format). + File with .crt extention contain openssl "text output" for identity + files. Files with .p12 extention are for "Microsoft Windows keystore". + Note: .p12 = .pfx for Windows. + +4-cre_crls.sh: + Revoke part of client certificates. + +5-cre_ldap.sh + Create LDAP ldif files and slapd config. + +verify.sh: + To check certificates against "Test CA". Note: check only + testid_*.crt and testhostkey_*.crt files in current directory. + +functions: + Common usefull functions. + +openssh_tests.sh: + Main test script - call other testscripts. + +test-blob_auth.sh.inc, +test-dn_auth_file.sh.inc, +test-dn_auth_path.sh.inc, +test-agent.sh.inc, +test-crl.sh.inc, +test-self.sh.inc, +test-alg.sh.inc, +test-ocsp.sh.inc, +test-by_ldap.sh.inc: + Test shell scripts. See DESCRIPTION in each file. + +Note that hostbased authentication we cannot test without to install. +Generated testhostkey_* certificates are with sslserver and sslclient +purposes and you can use them to test manually hostbased authentication. + + +4.) Troubleshooting +"make check-certs" fails on: + +4.1.) "generating a new ... private key for the TEST CA ..." +Usually this happen on system without /dev/{u}random. +In file [BUILDDIR]/tests/CA/openssh_ca-2.log we can see a message: +"... PRNG not seeded ...". +Read again WARNING.RNG from OpenSSH sourcedir and/or +http://www.openssl.org/support/faq.html + +4.1.1.) reconfigure your system and/or openssl +4.1.2.) or do next +4.1.2.1.) install OpenSSH :-( otherwise later "make check-certs" +(ssh-keygen) fail with message: +"couldn't exec '.../libexec/ssh-rand-helper': ..." +and second ./ssh-rand-helper fail with message: +"couldn't read entropy commands file ../ssh_prng_cmds: ..." +Tip: configure OpenSSH with prefix for example $HOME/test + +4.1.2.2.) run: +ssh-rand-helper +rm -f $HOME/.rnd +ln -s .ssh/prng_seed $HOME/.rnd + +4.1.2.3.) test openssl with command: +/usr/local/ssl/bin/openssl genrsa -des3 -passout pass:change_it +Tip: before to create every key with OpenSSL run ssh-rand-helper ! + +4.1.2.4.) run again "... make check-certs ..." + +4.2.) fail on first check: "* rsa_md5 valid blob failed" +- Usually SUDO command is not set. See p. 3.1.2.1. +- When you build with tcpwrappers your hosts.allow must permit +connections from localhost, otherwise you can see in failed message +text like this: "... connection closed by remote host ..." + +4.3.) fail on "starting OCSP responder(XXX) on YYY:NNNNN failed" +- Ensure sequence of about six free ports and use SSH_VA_BASEPORT + to specify first of them. +- Ensure enough timeout previous running OCSP responders to free + ports. Increase value of SSH_OPENSLL_OCSP_TMOUT in test config file. + + +5.) FAQ + +Q.) How to convert a certificate from DER to PEM format? +A.) Run command "openssl x509 ..." with command line options +-inform/-outform - you can select one of formats: DER, NET or PEM. +The default is PEM. + +Q.) How to convert pfx to p12 file? +A.) Just change file extension ;-). + +Q.) How to use my p12 file in OpenSSH as identity? +A.) Run commands: +$ openssl pkcs12 -in FILE.p12 -clcerts > id_x509 +$ ssh-keygen -f id_x509 -y > id_x509.pub + Don't forget to set properly permition on file id_x509, as +example "chmod 600 id_x509". + Note name of identity file can be one of defaults: + 'id_rsa' or 'id_dsa'. + Configure client. + +Q.) How to use p12 file in OpenSSH as hostkey? +A.) Note that host keys are password less! + It is similar to client identity. + Remember umask settings. + Run as root commands: +# umask 0077 +# openssl pkcs12 -in FILE.p12 -clcerts > ssh_host_x509 + Note: you must enter export password! +# ssh-keygen -p -f ssh_host_x509 -N '' + Now hostkey file is password less ! +# ssh-keygen -f ssh_host_x509 -y > ssh_host_x509.pub + Restore umask settings. + Note name of hostkey file can be one of defaults: + 'ssh_host_dsa_key' or 'ssh_host_rsa_key'. + Configure server, test configuration with command +# sshd -t ..../sshd_config + and start/restart the server. Don't forget to inform users + that hostkey is changed! + +Q.) How to import CA certificates and/or CRLs in LDAP? +A.) You should create a ldif file with LDAP entries that contains + binary atributes "cACertificate" and/or "certificateRevocationList" + and to specify path to file with certificate or CRL in DER format. + Entry should contain objectClass "pkiCA". See definition in core + LDAP schema. After this to use command ldapadd or ldapmodify to + add/modify LDAP data. See command manual pages. + + As example when you build OpenSSH with ldap queries after + regression test see content of file + $(top_builddir)/tests/CA/ldap/ca.ldif . + This file is created by the script + $(srcdir)/tests/CA/5-cre_ldap.sh + and entries are added to LDAP with command: +# ldapadd -x -w secret -D cn=... -H ldap://... \ + -f .../ca.ldif . + See ldapadd manual page for options meaning. + +Enjoy ;-) diff -ruN openssh-4.2p1/scp.0 openssh-4.2p1+x509-5.5/scp.0 --- openssh-4.2p1/scp.0 2005-09-01 12:15:24.000000000 +0300 +++ openssh-4.2p1+x509-5.5/scp.0 2006-04-26 00:05:18.000000000 +0300 @@ -1,4 +1,4 @@ -SCP(1) OpenBSD Reference Manual SCP(1) +SCP(1) System General Commands Manual SCP(1) NAME scp - secure copy (remote file copy program) @@ -28,8 +28,8 @@ -6 Forces scp to use IPv6 addresses only. - -B Selects batch mode (prevents asking for passwords or passphras- - es). + -B Selects batch mode (prevents asking for passwords or + passphrases). -C Compression enable. Passes the -C flag to ssh(1) to enable com- pression. @@ -54,56 +54,7 @@ Can be used to pass options to ssh in the format used in ssh_config(5). This is useful for specifying options for which there is no separate scp command-line flag. For full details of - the options listed below, and their possible values, see - ssh_config(5). - - AddressFamily - BatchMode - BindAddress - ChallengeResponseAuthentication - CheckHostIP - Cipher - Ciphers - Compression - CompressionLevel - ConnectionAttempts - ConnectTimeout - ControlMaster - ControlPath - GlobalKnownHostsFile - GSSAPIAuthentication - GSSAPIDelegateCredentials - HashKnownHosts - Host - HostbasedAuthentication - HostKeyAlgorithms - HostKeyAlias - HostName - IdentityFile - IdentitiesOnly - KbdInteractiveDevices - LogLevel - MACs - NoHostAuthenticationForLocalhost - NumberOfPasswordPrompts - PasswordAuthentication - Port - PreferredAuthentications - Protocol - ProxyCommand - PubkeyAuthentication - RhostsRSAAuthentication - RSAAuthentication - SendEnv - ServerAliveInterval - ServerAliveCountMax - SmartcardDevice - StrictHostKeyChecking - TCPKeepAlive - UsePrivilegedPort - User - UserKnownHostsFile - VerifyHostKeyDNS + the options and their possible values, see ssh_config(5). -P port Specifies the port to connect to on the remote host. Note that @@ -141,4 +92,4 @@ Timo Rinne Tatu Ylonen -OpenBSD 3.8 September 25, 1999 3 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/scp.1 openssh-4.2p1+x509-5.5/scp.1 --- openssh-4.2p1/scp.1 2005-03-02 03:04:16.000000000 +0200 +++ openssh-4.2p1+x509-5.5/scp.1 2005-09-02 09:06:00.000000000 +0300 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.38 2005/03/01 17:19:35 jmc Exp $ +.\" $OpenBSD$ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -113,58 +113,8 @@ for which there is no separate .Nm scp command-line flag. -For full details of the options listed below, and their possible values, see +For full details of the options and their possible values, see .Xr ssh_config 5 . -.Pp -.Bl -tag -width Ds -offset indent -compact -.It AddressFamily -.It BatchMode -.It BindAddress -.It ChallengeResponseAuthentication -.It CheckHostIP -.It Cipher -.It Ciphers -.It Compression -.It CompressionLevel -.It ConnectionAttempts -.It ConnectTimeout -.It ControlMaster -.It ControlPath -.It GlobalKnownHostsFile -.It GSSAPIAuthentication -.It GSSAPIDelegateCredentials -.It HashKnownHosts -.It Host -.It HostbasedAuthentication -.It HostKeyAlgorithms -.It HostKeyAlias -.It HostName -.It IdentityFile -.It IdentitiesOnly -.It KbdInteractiveDevices -.It LogLevel -.It MACs -.It NoHostAuthenticationForLocalhost -.It NumberOfPasswordPrompts -.It PasswordAuthentication -.It Port -.It PreferredAuthentications -.It Protocol -.It ProxyCommand -.It PubkeyAuthentication -.It RhostsRSAAuthentication -.It RSAAuthentication -.It SendEnv -.It ServerAliveInterval -.It ServerAliveCountMax -.It SmartcardDevice -.It StrictHostKeyChecking -.It TCPKeepAlive -.It UsePrivilegedPort -.It User -.It UserKnownHostsFile -.It VerifyHostKeyDNS -.El .It Fl P Ar port Specifies the port to connect to on the remote host. Note that this option is written with a capital diff -ruN openssh-4.2p1/servconf.c openssh-4.2p1+x509-5.5/servconf.c --- openssh-4.2p1/servconf.c 2005-08-12 15:11:37.000000000 +0300 +++ openssh-4.2p1+x509-5.5/servconf.c 2006-04-26 09:06:01.000000000 +0300 @@ -7,14 +7,38 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X509 certificate support, + * Copyright (c) 2002-2006 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" -RCSID("$OpenBSD: servconf.c,v 1.144 2005/08/06 10:03:12 dtucker Exp $"); +RCSID("$OpenBSD$"); #include "ssh.h" #include "log.h" #include "servconf.h" +#include "ssh-xkalg.h" #include "xmalloc.h" #include "compat.h" #include "pathnames.h" @@ -102,6 +126,21 @@ options->authorized_keys_file2 = NULL; options->num_accept_env = 0; + options->hostbased_algorithms = NULL; + options->pubkey_algorithms = NULL; + /* Supported X.509 key algorithms and signatures + are defined is external source. */ + options->x509flags = &ssh_x509flags; + ssh_x509flags_initialize(options->x509flags, 1); +#ifndef SSH_X509STORE_DISABLED + ssh_x509store_initialize(&options->ca); +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + options->va.type = -1; + options->va.certificate_file = NULL; + options->va.responder_url = NULL; +#endif /*def SSH_OCSP_ENABLED*/ + /* Needs to be accessable in many places */ use_privsep = -1; } @@ -230,6 +269,20 @@ if (options->authorized_keys_file == NULL) options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; + /* options->hostbased_algorithms */ + /* options->pubkey_algorithms */ + fill_default_xkalg(); + ssh_x509flags_defaults(options->x509flags); +#ifndef SSH_X509STORE_DISABLED + ssh_x509store_system_defaults(&options->ca); + ssh_x509store_addlocations(&options->ca); +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + if (options->va.type == -1) + options->va.type = ssh_get_default_vatype(); + ssh_set_validator(&options->va); +#endif /*def SSH_OCSP_ENABLED*/ + /* Turn privilege separation on by default */ if (use_privsep == -1) use_privsep = 1; @@ -242,7 +295,14 @@ options->compression = 0; } #endif - + if (options->hostbased_algorithms != NULL) + if (!key_names_valid2(options->hostbased_algorithms)) + fatal("Bad protocol 2 hostbased algorithms '%s'.", + options->hostbased_algorithms); + if (options->pubkey_algorithms != NULL) + if (!key_names_valid2(options->pubkey_algorithms)) + fatal("Bad protocol 2 public key algorithms '%s'.", + options->pubkey_algorithms); } /* Keyword tokens. */ @@ -272,6 +332,16 @@ sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sUsePrivilegeSeparation, + sHostbasedAlgorithms, + sPubkeyAlgorithms, + sX509KeyAlgorithm, + sAllowedClientCertPurpose, + sKeyAllowSelfIssued, sMandatoryCRL, + sCACertificateFile, sCACertificatePath, + sCARevocationFile, sCARevocationPath, + sCAldapVersion, sCAldapURL, + sVAType, sVACertificateFile, + sVAOCSPResponderURL, sDeprecated, sUnsupported } ServerOpCodes; @@ -373,6 +443,22 @@ { "authorizedkeysfile2", sAuthorizedKeysFile2 }, { "useprivilegeseparation", sUsePrivilegeSeparation}, { "acceptenv", sAcceptEnv }, + { "hostbasedalgorithms", sHostbasedAlgorithms }, + { "pubkeyalgorithms", sPubkeyAlgorithms }, + { "x509rsasigtype", sDeprecated }, + { "x509keyalgorithm", sX509KeyAlgorithm }, + { "allowedcertpurpose", sAllowedClientCertPurpose }, + { "keyallowselfissued", sKeyAllowSelfIssued } , + { "mandatorycrl", sMandatoryCRL } , + { "cacertificatefile", sCACertificateFile }, + { "cacertificatepath", sCACertificatePath }, + { "carevocationfile", sCARevocationFile }, + { "carevocationpath", sCARevocationPath }, + { "caldapversion", sCAldapVersion }, + { "caldapurl", sCAldapURL }, + { "vatype", sVAType }, + { "vacertificatefile", sVACertificateFile }, + { "vaocspresponderurl", sVAOCSPResponderURL }, { NULL, sBadOption } }; @@ -962,6 +1048,142 @@ } break; + case sHostbasedAlgorithms: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + /* cannot validate here - depend from X509KeyAlgorithm + if (!key_names_valid2(arg)) + fatal("%.200s line %d: Bad protocol 2 hostbased algorithms '%s'.", + filename, linenum, arg ? arg : ""); + */ + if (options->hostbased_algorithms == NULL) + options->hostbased_algorithms = xstrdup(arg); + break; + + case sPubkeyAlgorithms: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + /* cannot validate here - depend from X509KeyAlgorithm + if (!key_names_valid2(arg)) + fatal("%.200s line %d: Bad protocol 2 public key algorithms '%s'.", + filename, linenum, arg ? arg : ""); + */ + if (options->pubkey_algorithms == NULL) + options->pubkey_algorithms = xstrdup(arg); + break; + + case sX509KeyAlgorithm: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + if (ssh_add_x509key_alg(arg) < 0) { + fatal("%.200s line %d: Bad X.509 key algorithm '%.200s'.", + filename, linenum, arg); + } + break; + + case sAllowedClientCertPurpose: + intptr = &options->x509flags->allowedcertpurpose; + arg = strdelim(&cp); + if (arg && *arg) { + if (strcasecmp(arg, "skip") == 0) goto skip_purpose; + + /* convert string to OpenSSL index */ + value = ssh_get_x509purpose_s (1, arg); + if (value < 0) + fatal("%.200s line %d: Bad certificate purpose '%.30s'.", + filename, linenum, arg); + + if (*intptr == -1) + *intptr = value; + } else { +skip_purpose: + if (*intptr == -1) { + *intptr = -2; + verbose("%.200s line %d: option is set to don`t check certificate purpose.", + filename, linenum); + } + } + break; + +#ifndef SSH_X509STORE_DISABLED + case sKeyAllowSelfIssued: + intptr = &options->x509flags->key_allow_selfissued; + goto parse_flag; + + case sMandatoryCRL: + intptr = &options->x509flags->mandatory_crl; + goto parse_flag; + + case sCACertificateFile: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.certificate_file; +parse_string: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*charptr == NULL) + *charptr = xstrdup(arg); + break; + + case sCACertificatePath: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.certificate_path; + goto parse_string; + + case sCARevocationFile: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.revocation_file; + goto parse_string; + + case sCARevocationPath: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.revocation_path; + goto parse_string; +#endif /*ndef SSH_X509STORE_DISABLED*/ + +#ifdef LDAP_ENABLED + case sCAldapVersion: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.ldap_ver; + goto parse_string; + + case sCAldapURL: + /* X509StoreOptions prefered type is 'const char*' */ + charptr = (char**)&options->ca.ldap_url; + goto parse_string; +#endif /*def LDAP_ENABLED*/ + +#ifdef SSH_OCSP_ENABLED + case sVAType: + intptr = &options->va.type; + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + + value = ssh_get_vatype_s(arg); + if (value < 0) { + fatal("%.200s line %d: Bad OCSP responder type '%.30s'.", + filename, linenum, arg); + } + + if (*intptr == -1) + *intptr = value; + break; + + case sVACertificateFile: + /* VAOptions prefered type is 'const char*' */ + charptr = (char**)&options->va.certificate_file; + goto parse_string; + + case sVAOCSPResponderURL: + /* VAOptions prefered type is 'const char*' */ + charptr = (char**)&options->va.responder_url; + goto parse_string; +#endif /*def SSH_OCSP_ENABLED*/ + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -969,6 +1191,23 @@ arg = strdelim(&cp); break; +#ifdef SSH_X509STORE_DISABLED + case sKeyAllowSelfIssued: + case sMandatoryCRL: + case sCACertificateFile: + case sCACertificatePath: + case sCARevocationFile: + case sCARevocationPath: +#endif /*def SSH_X509STORE_DISABLED*/ +#ifndef LDAP_ENABLED + case sCAldapVersion: + case sCAldapURL: +#endif /*ndef LDAP_ENABLED*/ +#ifndef SSH_OCSP_ENABLED + case sVAType: + case sVACertificateFile: + case sVAOCSPResponderURL: +#endif /*ndef SSH_OCSP_ENABLED*/ case sUnsupported: logit("%s line %d: Unsupported option %s", filename, linenum, arg); diff -ruN openssh-4.2p1/servconf.h openssh-4.2p1+x509-5.5/servconf.h --- openssh-4.2p1/servconf.h 2005-01-20 01:57:56.000000000 +0200 +++ openssh-4.2p1+x509-5.5/servconf.h 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.71 2004/12/23 23:11:00 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -11,12 +11,36 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X509 certificate support, + * Copyright (c) 2002-2006 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. */ #ifndef SERVCONF_H #define SERVCONF_H #include "buffer.h" +#include "x509store.h" #define MAX_PORTS 256 /* Max # ports. */ @@ -134,6 +158,23 @@ char *authorized_keys_file; /* File containing public keys */ char *authorized_keys_file2; int use_pam; /* Enable auth via PAM */ + + char* hostbased_algorithms; /* Allowed hostbased algorithms. */ + char* pubkey_algorithms; /* Allowed pubkey algorithms. */ + + /* Supported X.509 key algorithms and signatures + are defined is external source. */ + + /* sshd PKI(X509) flags */ + SSH_X509Flags *x509flags; +#ifndef SSH_X509STORE_DISABLED + /* sshd PKI(X509) system store */ + X509StoreOptions ca; +#endif /*ndef SSH_X509STORE_DISABLED*/ +#ifdef SSH_OCSP_ENABLED + /* ssh X.509 extra validation */ + VAOptions va; +#endif /*def SSH_OCSP_ENABLED*/ } ServerOptions; void initialize_server_options(ServerOptions *); diff -ruN openssh-4.2p1/sftp.0 openssh-4.2p1+x509-5.5/sftp.0 --- openssh-4.2p1/sftp.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sftp.0 2006-04-26 00:05:20.000000000 +0300 @@ -1,4 +1,4 @@ -SFTP(1) OpenBSD Reference Manual SFTP(1) +SFTP(1) System General Commands Manual SFTP(1) NAME sftp - secure file transfer program @@ -15,8 +15,8 @@ sftp is an interactive file transfer program, similar to ftp(1), which performs all operations over an encrypted ssh(1) transport. It may also use many features of ssh, such as public key authentication and compres- - sion. sftp connects and logs into the specified host, then enters an in- - teractive command mode. + sion. sftp connects and logs into the specified host, then enters an + interactive command mode. The second usage format will retrieve files automatically if a non-inter- active authentication method is used; otherwise it will do so after suc- @@ -37,8 +37,8 @@ higher memory consumption. The default is 32768 bytes. -b batchfile - Batch mode reads a series of commands from an input batchfile in- - stead of stdin. Since it lacks user interaction it should be + Batch mode reads a series of commands from an input batchfile + instead of stdin. Since it lacks user interaction it should be used in conjunction with non-interactive authentication. A batchfile of `-' may be used to indicate standard input. sftp will abort if any of the following commands fail: get, put, @@ -58,56 +58,7 @@ ssh_config(5). This is useful for specifying options for which there is no separate sftp command-line flag. For example, to specify an alternate port use: sftp -oPort=24. For full details - of the options listed below, and their possible values, see - ssh_config(5). - - AddressFamily - BatchMode - BindAddress - ChallengeResponseAuthentication - CheckHostIP - Cipher - Ciphers - Compression - CompressionLevel - ConnectionAttempts - ConnectTimeout - ControlMaster - ControlPath - GlobalKnownHostsFile - GSSAPIAuthentication - GSSAPIDelegateCredentials - HashKnownHosts - Host - HostbasedAuthentication - HostKeyAlgorithms - HostKeyAlias - HostName - IdentityFile - IdentitiesOnly - KbdInteractiveDevices - LogLevel - MACs - NoHostAuthenticationForLocalhost - NumberOfPasswordPrompts - PasswordAuthentication - Port - PreferredAuthentications - Protocol - ProxyCommand - PubkeyAuthentication - RhostsRSAAuthentication - RSAAuthentication - SendEnv - ServerAliveInterval - ServerAliveCountMax - SmartcardDevice - StrictHostKeyChecking - TCPKeepAlive - UsePrivilegedPort - User - UserKnownHostsFile - VerifyHostKeyDNS + of the options and their possible values, see ssh_config(5). -P sftp_server_path Connect directly to a local sftp server (rather than via ssh(1)). @@ -160,10 +111,10 @@ Retrieve the remote-path and store it on the local machine. If the local path name is not specified, it is given the same name it has on the remote machine. remote-path may contain glob(3) - characters and may match multiple files. If it does and local- - path is specified, then local-path must specify a directory. If - the -P flag is specified, then full file permissions and access - times are copied too. + characters and may match multiple files. If it does and + local-path is specified, then local-path must specify a direc- + tory. If the -P flag is specified, then full file permissions + and access times are copied too. help Display help text. @@ -221,10 +172,10 @@ Toggle display of progress meter. put [-P] local-path [remote-path] - Upload local-path and store it on the remote machine. If the re- - mote path name is not specified, it is given the same name it has - on the local machine. local-path may contain glob(3) characters - and may match multiple files. If it does and remote-path is + Upload local-path and store it on the remote machine. If the + remote path name is not specified, it is given the same name it + has on the local machine. local-path may contain glob(3) charac- + ters and may match multiple files. If it does and remote-path is specified, then remote-path must specify a directory. If the -P flag is specified, then the file's full permission and access time are copied too. @@ -262,4 +213,4 @@ T. Ylonen and S. Lehtinen, SSH File Transfer Protocol, draft-ietf-secsh- filexfer-00.txt, January 2001, work in progress material. -OpenBSD 3.8 February 4, 2001 4 +BSD February 4, 2001 BSD diff -ruN openssh-4.2p1/sftp.1 openssh-4.2p1+x509-5.5/sftp.1 --- openssh-4.2p1/sftp.1 2005-03-02 03:04:16.000000000 +0200 +++ openssh-4.2p1+x509-5.5/sftp.1 2005-09-02 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.61 2005/03/01 17:19:35 jmc Exp $ +.\" $OpenBSD$ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -141,58 +141,8 @@ command-line flag. For example, to specify an alternate port use: .Ic sftp -oPort=24 . -For full details of the options listed below, and their possible values, see +For full details of the options and their possible values, see .Xr ssh_config 5 . -.Pp -.Bl -tag -width Ds -offset indent -compact -.It AddressFamily -.It BatchMode -.It BindAddress -.It ChallengeResponseAuthentication -.It CheckHostIP -.It Cipher -.It Ciphers -.It Compression -.It CompressionLevel -.It ConnectionAttempts -.It ConnectTimeout -.It ControlMaster -.It ControlPath -.It GlobalKnownHostsFile -.It GSSAPIAuthentication -.It GSSAPIDelegateCredentials -.It HashKnownHosts -.It Host -.It HostbasedAuthentication -.It HostKeyAlgorithms -.It HostKeyAlias -.It HostName -.It IdentityFile -.It IdentitiesOnly -.It KbdInteractiveDevices -.It LogLevel -.It MACs -.It NoHostAuthenticationForLocalhost -.It NumberOfPasswordPrompts -.It PasswordAuthentication -.It Port -.It PreferredAuthentications -.It Protocol -.It ProxyCommand -.It PubkeyAuthentication -.It RhostsRSAAuthentication -.It RSAAuthentication -.It SendEnv -.It ServerAliveInterval -.It ServerAliveCountMax -.It SmartcardDevice -.It StrictHostKeyChecking -.It TCPKeepAlive -.It UsePrivilegedPort -.It User -.It UserKnownHostsFile -.It VerifyHostKeyDNS -.El .It Fl P Ar sftp_server_path Connect directly to a local sftp server (rather than via diff -ruN openssh-4.2p1/sftp-server.0 openssh-4.2p1+x509-5.5/sftp-server.0 --- openssh-4.2p1/sftp-server.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sftp-server.0 2006-04-26 00:05:19.000000000 +0300 @@ -1,4 +1,4 @@ -SFTP-SERVER(8) OpenBSD System Manager's Manual SFTP-SERVER(8) +SFTP-SERVER(8) System Manager's Manual SFTP-SERVER(8) NAME sftp-server - SFTP server subsystem @@ -8,9 +8,9 @@ DESCRIPTION sftp-server is a program that speaks the server side of SFTP protocol to - stdout and expects client requests from stdin. sftp-server is not in- - tended to be called directly, but from sshd(8) using the Subsystem op- - tion. See sshd_config(5) for more information. + stdout and expects client requests from stdin. sftp-server is not + intended to be called directly, but from sshd(8) using the Subsystem + option. See sshd_config(5) for more information. SEE ALSO sftp(1), ssh(1), sshd_config(5), sshd(8) @@ -24,4 +24,4 @@ HISTORY sftp-server first appeared in OpenBSD 2.8 . -OpenBSD 3.8 August 30, 2000 1 +BSD August 30, 2000 BSD diff -ruN openssh-4.2p1/ssh.0 openssh-4.2p1+x509-5.5/ssh.0 --- openssh-4.2p1/ssh.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh.0 2006-04-26 00:05:19.000000000 +0300 @@ -1,22 +1,22 @@ -SSH(1) OpenBSD Reference Manual SSH(1) +SSH(1) System General Commands Manual SSH(1) NAME ssh - OpenSSH SSH client (remote login program) SYNOPSIS ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec] - [-D port] [-e escape_char] [-F configfile] [-i identity_file] - [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] - [-O ctl_cmd] [-o option] [-p port] - [-R [bind_address:]port:host:hostport] [-S ctl_path] [user@]hostname + [-D port] [-e escape_char] [-F configfile] [-i identity_file] [-L + [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] + [-O ctl_cmd] [-o option] [-p port] [-R + [bind_address:]port:host:hostport] [-S ctl_path] [user@]hostname [command] DESCRIPTION ssh (SSH client) is a program for logging into a remote machine and for executing commands on a remote machine. It is intended to replace rlogin - and rsh, and provide secure encrypted communications between two untrust- - ed hosts over an insecure network. X11 connections and arbitrary TCP/IP - ports can also be forwarded over the secure channel. + and rsh, and provide secure encrypted communications between two + untrusted hosts over an insecure network. X11 connections and arbitrary + TCP/IP ports can also be forwarded over the secure channel. ssh connects and logs into the specified hostname (with optional user name). The user must prove his/her identity to the remote machine using @@ -38,8 +38,8 @@ only then is login permitted. This authentication method closes security holes due to IP spoofing, DNS spoofing and routing spoofing. [Note to the administrator: /etc/hosts.equiv, ~/.rhosts, and the rlogin/rsh proto- - col in general, are inherently insecure and should be disabled if securi- - ty is desired.] + col in general, are inherently insecure and should be disabled if secu- + rity is desired.] As a second authentication method, ssh supports RSA based authentication. The scheme is based on public-key cryptography: there are cryptosystems @@ -87,12 +87,13 @@ The public key method is similar to RSA authentication described in the previous section and allows the RSA or DSA algorithm to be used: The - client uses his private key, ~/.ssh/id_dsa or ~/.ssh/id_rsa, to sign the - session identifier and sends the result to the server. The server checks - whether the matching public key is listed in ~/.ssh/authorized_keys and - grants access if both the key is found and the signature is correct. The - session identifier is derived from a shared Diffie-Hellman value and is - only known to the client and the server. + client uses his private key, ~/.ssh/id_dsa or ~/.ssh/id_rsa, which can + contain a X.509 certificate in addition to key to sign the session iden- + tifier and sends the result to the server. The server checks whether the + matching public key or certificate is listed in ~/.ssh/authorized_keys + and grants access if both the key is found and the signature is correct. + The session identifier is derived from a shared Diffie-Hellman value and + is only known to the client and the server. If public key authentication fails or is not available, a password can be sent encrypted to the remote host to prove the user's identity. @@ -101,13 +102,13 @@ tion. Protocol 2 provides additional mechanisms for confidentiality (the traf- - fic is encrypted using AES, 3DES, Blowfish, CAST128 or Arcfour) and in- - tegrity (hmac-md5, hmac-sha1, hmac-ripemd160). Note that protocol 1 + fic is encrypted using AES, 3DES, Blowfish, CAST128 or Arcfour) and + integrity (hmac-md5, hmac-sha1, hmac-ripemd160). Note that protocol 1 lacks a strong mechanism for ensuring the integrity of the connection. Login session and remote execution - When the user's identity has been accepted by the server, the server ei- - ther executes the given command, or logs into the machine and gives the + When the user's identity has been accepted by the server, the server + either executes the given command, or logs into the machine and gives the user a normal shell on the remote machine. All communication with the remote command or shell will be automatically encrypted. @@ -150,8 +151,8 @@ version 2 and if the peer supports it). ~C Open command line. Currently this allows the addition of port - forwardings using the -L and -R options (see below). It also al- - lows the cancellation of existing remote port-forwardings using + forwardings using the -L and -R options (see below). It also + allows the cancellation of existing remote port-forwardings using -KR hostport. Basic help is available, using the -h option. ~R Request rekeying of the connection (only useful for SSH protocol @@ -162,11 +163,11 @@ the -X and -x options described later) and the user is using X11 (the DISPLAY environment variable is set), the connection to the X11 display is automatically forwarded to the remote side in such a way that any X11 - programs started from the shell (or command) will go through the encrypt- - ed channel, and the connection to the real X server will be made from the - local machine. The user should not manually set DISPLAY. Forwarding of - X11 connections can be configured on the command line or in configuration - files. + programs started from the shell (or command) will go through the + encrypted channel, and the connection to the real X server will be made + from the local machine. The user should not manually set DISPLAY. For- + warding of X11 connections can be configured on the command line or in + configuration files. The DISPLAY value set by ssh will point to the server machine, but with a display number greater than zero. This is normal, and happens because @@ -196,17 +197,17 @@ ~/.ssh/known_hosts in the user's home directory. Additionally, the file /etc/ssh/ssh_known_hosts is automatically checked for known hosts. Any new hosts are automatically added to the user's file. If a host's iden- - tification ever changes, ssh warns about this and disables password au- - thentication to prevent a trojan horse from getting the user's password. - Another purpose of this mechanism is to prevent man-in-the-middle attacks - which could otherwise be used to circumvent the encryption. The + tification ever changes, ssh warns about this and disables password + authentication to prevent a trojan horse from getting the user's pass- + word. Another purpose of this mechanism is to prevent man-in-the-middle + attacks which could otherwise be used to circumvent the encryption. The StrictHostKeyChecking option can be used to prevent logins to machines whose host key is not known or has changed. - ssh can be configured to verify host identification using fingerprint re- - source records (SSHFP) published in DNS. The VerifyHostKeyDNS option can - be used to control how DNS lookups are performed. SSHFP resource records - can be generated using ssh-keygen(1). + ssh can be configured to verify host identification using fingerprint + resource records (SSHFP) published in DNS. The VerifyHostKeyDNS option + can be used to control how DNS lookups are performed. SSHFP resource + records can be generated using ssh-keygen(1). The options are as follows: @@ -234,8 +235,8 @@ -b bind_address Use bind_address on the local machine as the source address of - the connection. Only useful on systems with more than one ad- - dress. + the connection. Only useful on systems with more than one + address. -C Requests compression of all data (including stdin, stdout, stderr, and data for forwarded X11 and TCP/IP connections). The @@ -297,26 +298,27 @@ default for the per-user configuration file is ~/.ssh/config. -f Requests ssh to go to background just before command execution. - This is useful if ssh is going to ask for passwords or passphras- - es, but the user wants it in the background. This implies -n. - The recommended way to start X11 programs at a remote site is - with something like ssh -f host xterm. + This is useful if ssh is going to ask for passwords or + passphrases, but the user wants it in the background. This + implies -n. The recommended way to start X11 programs at a + remote site is with something like ssh -f host xterm. -g Allows remote hosts to connect to local forwarded ports. -I smartcard_device - Specifies which smartcard device to use. The argument is the de- - vice ssh should use to communicate with a smartcard used for + Specifies which smartcard device to use. The argument is the + device ssh should use to communicate with a smartcard used for storing the user's private RSA key. -i identity_file Selects a file from which the identity (private key) for RSA or DSA authentication is read. The default is ~/.ssh/identity for protocol version 1, and ~/.ssh/id_rsa and ~/.ssh/id_dsa for pro- - tocol version 2. Identity files may also be specified on a per- - host basis in the configuration file. It is possible to have - multiple -i options (and multiple identities specified in config- - uration files). + tocol version 2. For protocol version 2 is possible identity to + contain in addition X.509 certificate that match private key. + Identity files may also be specified on a per-host basis in the + configuration file. It is possible to have multiple -i options + (and multiple identities specified in configuration files). -k Disables forwarding (delegation) of GSSAPI credentials to the server. @@ -330,15 +332,15 @@ the secure channel, and a connection is made to host port hostport from the remote machine. Port forwardings can also be specified in the configuration file. IPv6 addresses can be spec- - ified with an alternative syntax: [bind_address/]port/host/host- - port or by enclosing the address in square brackets. Only the - superuser can forward privileged ports. By default, the local - port is bound in accordance with the GatewayPorts setting. How- - ever, an explicit bind_address may be used to bind the connection - to a specific address. The bind_address of ``localhost'' indi- - cates that the listening port be bound for local use only, while - an empty address or `*' indicates that the port should be avail- - able from all interfaces. + ified with an alternative syntax: + [bind_address/]port/host/hostport or by enclosing the address in + square brackets. Only the superuser can forward privileged + ports. By default, the local port is bound in accordance with + the GatewayPorts setting. However, an explicit bind_address may + be used to bind the connection to a specific address. The + bind_address of ``localhost'' indicates that the listening port + be bound for local use only, while an empty address or `*' indi- + cates that the port should be available from all interfaces. -l login_name Specifies the user to log in as on the remote machine. This also @@ -358,12 +360,13 @@ -n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background. A - common trick is to use this to run X11 programs on a remote ma- - chine. For example, ssh -n shadows.cs.hut.fi emacs & will start - an emacs on shadows.cs.hut.fi, and the X11 connection will be au- - tomatically forwarded over an encrypted channel. The ssh program - will be put in the background. (This does not work if ssh needs - to ask for a password or passphrase; see also the -f option.) + common trick is to use this to run X11 programs on a remote + machine. For example, ssh -n shadows.cs.hut.fi emacs & will + start an emacs on shadows.cs.hut.fi, and the X11 connection will + be automatically forwarded over an encrypted channel. The ssh + program will be put in the background. (This does not work if + ssh needs to ask for a password or passphrase; see also the -f + option.) -O ctl_cmd Control an active connection multiplexing master process. When @@ -375,66 +378,8 @@ -o option Can be used to give options in the format used in the configura- tion file. This is useful for specifying options for which there - is no separate command-line flag. For full details of the op- - tions listed below, and their possible values, see ssh_config(5). - - AddressFamily - BatchMode - BindAddress - ChallengeResponseAuthentication - CheckHostIP - Cipher - Ciphers - ClearAllForwardings - Compression - CompressionLevel - ConnectionAttempts - ConnectTimeout - ControlMaster - ControlPath - DynamicForward - EscapeChar - ForwardAgent - ForwardX11 - ForwardX11Trusted - GatewayPorts - GlobalKnownHostsFile - GSSAPIAuthentication - GSSAPIDelegateCredentials - HashKnownHosts - Host - HostbasedAuthentication - HostKeyAlgorithms - HostKeyAlias - HostName - IdentityFile - IdentitiesOnly - KbdInteractiveDevices - LocalForward - LogLevel - MACs - NoHostAuthenticationForLocalhost - NumberOfPasswordPrompts - PasswordAuthentication - Port - PreferredAuthentications - Protocol - ProxyCommand - PubkeyAuthentication - RemoteForward - RhostsRSAAuthentication - RSAAuthentication - SendEnv - ServerAliveInterval - ServerAliveCountMax - SmartcardDevice - StrictHostKeyChecking - TCPKeepAlive - UsePrivilegedPort - User - UserKnownHostsFile - VerifyHostKeyDNS - XAuthLocation + is no separate command-line flag. For full details of the + options and their possible values, see ssh_config(5). -p port Port to connect to on the remote host. This can be specified on @@ -461,8 +406,8 @@ the loopback interface only. This may be overriden by specifying a bind_address. An empty bind_address, or the address `*', indi- cates that the remote socket should listen on all interfaces. - Specifying a remote bind_address will only succeed if the serv- - er's GatewayPorts option is enabled (see sshd_config(5)). + Specifying a remote bind_address will only succeed if the + server's GatewayPorts option is enabled (see sshd_config(5)). -S ctl_path Specifies the location of a control socket for connection shar- @@ -470,9 +415,9 @@ in ssh_config(5) for details. -s May be used to request invocation of a subsystem on the remote - system. Subsystems are a feature of the SSH2 protocol which fa- - cilitate the use of SSH as a secure transport for other applica- - tions (eg. sftp(1)). The subsystem is specified as the remote + system. Subsystems are a feature of the SSH2 protocol which + facilitate the use of SSH as a secure transport for other appli- + cations (eg. sftp(1)). The subsystem is specified as the remote command. -T Disable pseudo-tty allocation. @@ -498,9 +443,9 @@ through the forwarded connection. An attacker may then be able to perform activities such as keystroke monitoring. - For this reason, X11 forwarding is subjected to X11 SECURITY ex- - tension restrictions by default. Please refer to the ssh -Y op- - tion and the ForwardX11Trusted directive in ssh_config(5) for + For this reason, X11 forwarding is subjected to X11 SECURITY + extension restrictions by default. Please refer to the ssh -Y + option and the ForwardX11Trusted directive in ssh_config(5) for more information. -x Disables X11 forwarding. @@ -550,8 +495,8 @@ SSH_CONNECTION Identifies the client and server ends of the connection. The - variable contains four space-separated values: client ip-ad- - dress, client port number, server ip-address and server port + variable contains four space-separated values: client ip- + address, client port number, server ip-address and server port number. SSH_ORIGINAL_COMMAND @@ -576,32 +521,40 @@ FILES ~/.ssh/known_hosts - Records host keys for all hosts the user has logged into that are - not in /etc/ssh/ssh_known_hosts. See sshd(8). + Records host keys or certificates for all hosts the user has + logged into that are not in /etc/ssh/ssh_known_hosts. See + sshd(8). ~/.ssh/identity, ~/.ssh/id_dsa, ~/.ssh/id_rsa Contains the authentication identity of the user. They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively. - These files contain sensitive data and should be readable by the - user but not accessible by others (read/write/execute). Note - that ssh ignores a private key file if it is accessible by oth- - ers. It is possible to specify a passphrase when generating the - key; the passphrase will be used to encrypt the sensitive part of - this file using 3DES. + It is possible protocol version 2 identity to contain private key + followed by X.509 certificate that match it. These files contain + sensitive data and should be readable by the user but not acces- + sible by others (read/write/execute). Note that ssh ignores a + private key file if it is accessible by others. It is possible + to specify a passphrase when generating the key; the passphrase + will be used to encrypt the sensitive part of this file using + 3DES. ~/.ssh/identity.pub, ~/.ssh/id_dsa.pub, ~/.ssh/id_rsa.pub Contains the public key for authentication (public part of the - identity file in human-readable form). The contents of the + identity file in human-readable form). Note that protocol ver- + sion 2 if a identity contain private key and X.509 certificate + this file must contain that certificate. The contents of the ~/.ssh/identity.pub file should be added to the file ~/.ssh/authorized_keys on all machines where the user wishes to log in using protocol version 1 RSA authentication. The contents of the ~/.ssh/id_dsa.pub and ~/.ssh/id_rsa.pub file should be added to ~/.ssh/authorized_keys on all machines where the user wishes to log in using protocol version 2 DSA/RSA authentication. + In case with X.509 certificates user can use ``new style''. + Instead to add content of file to authorized_keys user can write + certificate ``Distinguished Name''. See sshd(8) manual page. These files are not sensitive and can (but need not) be readable by anyone. These files are never used automatically and are not - necessary; they are only provided for the convenience of the us- - er. + necessary; they are only provided for the convenience of the + user. ~/.ssh/config This is the per-user configuration file. The file format and @@ -610,30 +563,32 @@ read/write for the user, and not accessible by others. ~/.ssh/authorized_keys - Lists the public keys (RSA/DSA) that can be used for logging in - as this user. The format of this file is described in the - sshd(8) manual page. In the simplest form the format is the same - as the .pub identity files. This file is not highly sensitive, - but the recommended permissions are read/write for the user, and - not accessible by others. + Lists the public keys (RSA/DSA) or certificates that can be used + for logging in as this user. The format of this file is + described in the sshd(8) manual page. In the simplest form the + format is the same as the .pub identity files. This file is not + highly sensitive, but the recommended permissions are read/write + for the user, and not accessible by others. /etc/ssh/ssh_known_hosts - Systemwide list of known host keys. This file should be prepared - by the system administrator to contain the public host keys of - all machines in the organization. This file should be world- - readable. This file contains public keys, one per line, in the - following format (fields separated by spaces): system name, pub- - lic key and optional comment field. When different names are - used for the same machine, all such names should be listed, sepa- - rated by commas. The format is described in the sshd(8) manual - page. + Systemwide list of known host keys or certificates. This file + should be prepared by the system administrator to contain the + public host keys or certificates of all machines in the organiza- + tion. This file should be world-readable. This file contains + public keys, one per line, in the following format (fields sepa- + rated by spaces): system name, public key and optional comment + field. When a X.509 certificate is used as host key instead of + public key line contain certificate (old style) or certificate + ``Distinguished Name''. When different names are used for the + same machine, all such names should be listed, separated by com- + mas. The format is described in the sshd(8) manual page. The canonical system name (as returned by name servers) is used by sshd(8) to verify the client host when logging in; other names are needed because ssh does not convert the user-supplied name to a canonical name before checking the key, because someone with - access to the name servers would then be able to fool host au- - thentication. + access to the name servers would then be able to fool host + authentication. /etc/ssh/ssh_config Systemwide configuration file. The file format and configuration @@ -643,12 +598,41 @@ /etc/ssh/ssh_host_rsa_key These three files contain the private parts of the host keys and are used for RhostsRSAAuthentication and HostbasedAuthentication. - If the protocol version 1 RhostsRSAAuthentication method is used, - ssh must be setuid root, since the host key is readable only by - root. For protocol version 2, ssh uses ssh-keysign(8) to access - the host keys for HostbasedAuthentication. This eliminates the + It is possible files to contain private part followed by X.509 + certificate that match it for protocol version 2 keys. If the + protocol version 1 RhostsRSAAuthentication method is used, ssh + must be setuid root, since the host key is readable only by root. + For protocol version 2, ssh uses ssh-keysign(8) to access the + host keys for HostbasedAuthentication. This eliminates the requirement that ssh be setuid root when that authentication - method is used. By default ssh is not setuid root. + method is used. By default ssh is not setuid root. When a cer- + tificate is used as host key for hostbased authentication that + certificate must have client purpose too or server configuration + must permit connection without client purpose. For allowed client + certificate purposes see ssh_config(5). + + /etc/ssh/ca/ca-bundle.crt and /etc/ssh/ca/ca-bundle.crl + Part of systemwide ``X.509 store''. The first file contain mul- + tiple certificates and the second ``Certificate Revocation List'' + (CRLs) of certificate signers in PEM format concatenated + together. Used in verification and validation of server host + certificate. + + /etc/ssh/ca/crt and /etc/ssh/ca/crl + Part of systemwide ``X.509 store''. ``Hash dirs'' with certifi- + cates, the first directory or CLRs, the second of certificate + signers. Each certificate should be stored in separate file with + name [HASH].[NUMBER] or [HASH].r[NUMBER] for the CRL, where + [HASH] is certificate or CRL hash value and [NUMBER] is an inte- + ger starting from zero. Used in verification and validation of + server host certificate. + + ~/.ssh/ca/ca-bundle.crt and ~/.ssh/ca/ca-bundle.crl + Part of user ``X.509 store''. Same as above systemwide files. + + ~/.ssh/ca/crt and ~/.ssh/ca/crl + Part of user ``X.509 store''. Same as above systemwide directo- + ries. ~/.rhosts This file is used in RhostsRSAAuthentication and @@ -675,8 +659,8 @@ ~/.shosts This file is used exactly the same way as .rhosts. The purpose for having this file is to be able to use RhostsRSAAuthentication - and HostbasedAuthentication authentication without permitting lo- - gin with rlogin or rsh(1). + and HostbasedAuthentication authentication without permitting + login with rlogin or rsh(1). /etc/hosts.equiv This file is used during RhostsRSAAuthentication and @@ -684,8 +668,8 @@ hosts names, one per line (the full format is described in the sshd(8) manual page). If the client host is found in this file, login is automatically permitted provided client and server user - names are the same. Additionally, successful client host key au- - thentication is required. This file should only be writable by + names are the same. Additionally, successful client host key + authentication is required. This file should only be writable by root. /etc/shosts.equiv @@ -723,8 +707,9 @@ AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo - de Raadt and Dug Song removed many bugs, re-added newer features and - created OpenSSH. Markus Friedl contributed the support for SSH protocol - versions 1.5 and 2.0. + 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 X.509 cer- + tificates. -OpenBSD 3.8 September 25, 1999 12 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/ssh.1 openssh-4.2p1+x509-5.5/ssh.1 --- openssh-4.2p1/ssh.1 2005-07-14 10:04:18.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh.1 2006-01-15 09:06:00.000000000 +0200 @@ -13,6 +13,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -34,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.209 2005/07/06 09:33:05 dtucker Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -209,8 +210,10 @@ .Pa ~/.ssh/id_dsa or .Pa ~/.ssh/id_rsa , +which can contain a X.509 certificate in addition to key to sign the session identifier and sends the result to the server. -The server checks whether the matching public key is listed in +The server checks whether the matching public key or certificate +is listed in .Pa ~/.ssh/authorized_keys and grants access if both the key is found and the signature is correct. The session identifier is derived from a shared Diffie-Hellman value @@ -560,6 +563,8 @@ and .Pa ~/.ssh/id_dsa for protocol version 2. +For protocol version 2 is possible identity to contain in addition +X.509 certificate that match private key. Identity files may also be specified on a per-host basis in the configuration file. It is possible to have multiple @@ -673,68 +678,8 @@ Can be used to give options in the format used in the configuration file. This is useful for specifying options for which there is no separate command-line flag. -For full details of the options listed below, and their possible values, see +For full details of the options and their possible values, see .Xr ssh_config 5 . -.Pp -.Bl -tag -width Ds -offset indent -compact -.It AddressFamily -.It BatchMode -.It BindAddress -.It ChallengeResponseAuthentication -.It CheckHostIP -.It Cipher -.It Ciphers -.It ClearAllForwardings -.It Compression -.It CompressionLevel -.It ConnectionAttempts -.It ConnectTimeout -.It ControlMaster -.It ControlPath -.It DynamicForward -.It EscapeChar -.It ForwardAgent -.It ForwardX11 -.It ForwardX11Trusted -.It GatewayPorts -.It GlobalKnownHostsFile -.It GSSAPIAuthentication -.It GSSAPIDelegateCredentials -.It HashKnownHosts -.It Host -.It HostbasedAuthentication -.It HostKeyAlgorithms -.It HostKeyAlias -.It HostName -.It IdentityFile -.It IdentitiesOnly -.It KbdInteractiveDevices -.It LocalForward -.It LogLevel -.It MACs -.It NoHostAuthenticationForLocalhost -.It NumberOfPasswordPrompts -.It PasswordAuthentication -.It Port -.It PreferredAuthentications -.It Protocol -.It ProxyCommand -.It PubkeyAuthentication -.It RemoteForward -.It RhostsRSAAuthentication -.It RSAAuthentication -.It SendEnv -.It ServerAliveInterval -.It ServerAliveCountMax -.It SmartcardDevice -.It StrictHostKeyChecking -.It TCPKeepAlive -.It UsePrivilegedPort -.It User -.It UserKnownHostsFile -.It VerifyHostKeyDNS -.It XAuthLocation -.El .It Fl p Ar port Port to connect to on the remote host. This can be specified on a @@ -959,14 +904,16 @@ .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/known_hosts -Records host keys for all hosts the user has logged into that are not -in +Records host keys or certificates for all hosts the user has logged +into that are not in .Pa /etc/ssh/ssh_known_hosts . See .Xr sshd 8 . .It Pa ~/.ssh/identity, ~/.ssh/id_dsa, ~/.ssh/id_rsa Contains the authentication identity of the user. They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively. +It is possible protocol version 2 identity to contain +private key followed by X.509 certificate that match it. These files contain sensitive data and should be readable by the user but not accessible by others (read/write/execute). @@ -979,6 +926,8 @@ .It Pa ~/.ssh/identity.pub, ~/.ssh/id_dsa.pub, ~/.ssh/id_rsa.pub Contains the public key for authentication (public part of the identity file in human-readable form). +Note that protocol version 2 if a identity contain private key and +X.509 certificate this file must contain that certificate. The contents of the .Pa ~/.ssh/identity.pub file should be added to the file @@ -993,6 +942,14 @@ .Pa ~/.ssh/authorized_keys on all machines where the user wishes to log in using protocol version 2 DSA/RSA authentication. +In case with X.509 certificates user can use +.Dq "new style" . +Instead to add content of file to authorized_keys user can write +certificate +.Dq "Distinguished Name" . +See +.Xr sshd 8 +manual page. These files are not sensitive and can (but need not) be readable by anyone. These files are @@ -1005,7 +962,8 @@ Because of the potential for abuse, this file must have strict permissions: read/write for the user, and not accessible by others. .It Pa ~/.ssh/authorized_keys -Lists the public keys (RSA/DSA) that can be used for logging in as this user. +Lists the public keys (RSA/DSA) or certificates that can be used for +logging in as this user. The format of this file is described in the .Xr sshd 8 manual page. @@ -1015,14 +973,17 @@ This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .It Pa /etc/ssh/ssh_known_hosts -Systemwide list of known host keys. +Systemwide list of known host keys or certificates. This file should be prepared by the -system administrator to contain the public host keys of all machines in the -organization. +system administrator to contain the public host keys or certificates +of all machines in the organization. This file should be world-readable. This file contains public keys, one per line, in the following format (fields separated by spaces): system name, public key and optional comment field. +When a X.509 certificate is used as host key instead of public key +line contain certificate (old style) or certificate +.Dq "Distinguished Name" . When different names are used for the same machine, all such names should be listed, separated by commas. @@ -1047,6 +1008,9 @@ .Cm RhostsRSAAuthentication and .Cm HostbasedAuthentication . +It is possible files to contain private part +followed by X.509 certificate that match it +for protocol version 2 keys. If the protocol version 1 .Cm RhostsRSAAuthentication method is used, @@ -1064,6 +1028,37 @@ By default .Nm is not setuid root. +When a certificate is used as host key for hostbased authentication +that certificate must have client purpose too or server configuration +must permit connection without client purpose. For allowed client +certificate purposes see +.Xr ssh_config 5 . +.It Pa "/etc/ssh/ca/ca-bundle.crt" and "/etc/ssh/ca/ca-bundle.crl" +Part of systemwide +.Dq "X.509 store" . +The first file contain multiple certificates and the second +.Dq "Certificate Revocation List" +(CRLs) of certificate signers in PEM format concatenated together. +Used in verification and validation of server host certificate. +.It Pa "/etc/ssh/ca/crt" and Pa "/etc/ssh/ca/crl" +Part of systemwide +.Dq "X.509 store" . +.Dq "Hash dirs" +with certificates, the first directory or CLRs, the second of +certificate signers. +Each certificate should be stored in separate file with name +[HASH].[NUMBER] or [HASH].r[NUMBER] for the CRL, where [HASH] is +certificate or CRL hash value and [NUMBER] is an integer starting +from zero. +Used in verification and validation of server host certificate. +.It Pa "~/.ssh/ca/ca-bundle.crt" and "~/.ssh/ca/ca-bundle.crl" +Part of user +.Dq "X.509 store" . +Same as above systemwide files. +.It Pa "~/.ssh/ca/crt" and Pa "~/.ssh/ca/crl" +Part of user +.Dq "X.509 store" . +Same as above systemwide directories. .It Pa ~/.rhosts This file is used in .Cm RhostsRSAAuthentication @@ -1189,3 +1184,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/ssh-add.0 openssh-4.2p1+x509-5.5/ssh-add.0 --- openssh-4.2p1/ssh-add.0 2005-09-01 12:15:24.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-add.0 2006-04-26 00:05:18.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-ADD(1) OpenBSD Reference Manual SSH-ADD(1) +SSH-ADD(1) System General Commands Manual SSH-ADD(1) NAME ssh-add - adds RSA or DSA identities to the authentication agent @@ -10,7 +10,8 @@ DESCRIPTION ssh-add adds RSA or DSA identities to the authentication agent, - ssh-agent(1). When run without arguments, it adds the files + ssh-agent(1). It is possible identity to contain in addition correspond- + ing X.509 certificate. When run without arguments, it adds the files ~/.ssh/id_rsa, ~/.ssh/id_dsa and ~/.ssh/identity. Alternative file names can be given on the command line. If any file requires a passphrase, ssh-add asks for the passphrase from the user. The passphrase is read @@ -36,8 +37,8 @@ -e reader Remove key in smartcard reader. - -L Lists public key parameters of all identities currently repre- - sented by the agent. + -L Lists public key or certificate parameters of all identities cur- + rently represented by the agent. -l Lists fingerprints of all identities currently represented by the agent. @@ -76,11 +77,13 @@ ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of - the user. + the user. It is possible to contain private key followed by + X.509 certificate that match it. ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of - the user. + the user. It is possible to contain private key followed by + X.509 certificate that match it. Identity files should not be readable by anyone but the user. Note that ssh-add ignores identity files if they are accessible by others. @@ -97,6 +100,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. + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- + tificates. -OpenBSD 3.8 September 25, 1999 2 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/ssh-add.1 openssh-4.2p1+x509-5.5/ssh-add.1 --- openssh-4.2p1/ssh-add.1 2005-05-26 05:04:02.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-add.1 2005-09-02 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-add.1,v 1.43 2005/04/21 06:17:50 djm Exp $ +.\" $OpenBSD$ .\" .\" -*- nroff -*- .\" @@ -16,6 +16,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -56,6 +57,8 @@ .Nm adds RSA or DSA identities to the authentication agent, .Xr ssh-agent 1 . +It is possible identity to contain in addition +corresponding X.509 certificate. When run without arguments, it adds the files .Pa ~/.ssh/id_rsa , .Pa ~/.ssh/id_dsa @@ -94,8 +97,8 @@ Remove key in smartcard .Ar reader . .It Fl L -Lists public key parameters of all identities currently represented -by the agent. +Lists public key or certificate parameters of +all identities currently represented by the agent. .It Fl l Lists fingerprints of all identities currently represented by the agent. .It Fl s Ar reader @@ -146,8 +149,12 @@ Contains the protocol version 1 RSA authentication identity of the user. .It Pa ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of the user. +It is possible to contain private key +followed by X.509 certificate that match it. .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. +It is possible to contain private key +followed by X.509 certificate that match it. .El .Pp Identity files should not be readable by anyone but the user. @@ -173,3 +180,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/ssh-add.c openssh-4.2p1+x509-5.5/ssh-add.c --- openssh-4.2p1/ssh-add.c 2005-07-17 10:22:46.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-add.c 2006-01-15 09:06:01.000000000 +0200 @@ -12,6 +12,8 @@ * * SSH2 implementation, * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * X.509 certificates support, + * 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 @@ -35,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-add.c,v 1.72 2005/07/17 07:17:55 djm Exp $"); +RCSID("$OpenBSD$"); #include @@ -48,6 +50,8 @@ #include "authfile.h" #include "pathnames.h" #include "misc.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" /* argv0 */ extern char *__progname; @@ -228,9 +232,20 @@ key_size(key), fp, comment, key_type(key)); xfree(fp); } else { +#ifndef SSH_X509STORE_DISABLED + if ((key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA)) { + /* key_write will print x509 certificate in blob format :-( */ + if(!x509key_write_subject(key, stdout)) + fprintf(stderr, "x509key_write_subject failed"); + fprintf(stdout, "\n"); + } else { +#endif /*ndef SSH_X509STORE_DISABLED*/ if (!key_write(key, stdout)) fprintf(stderr, "key_write failed"); fprintf(stdout, " %s\n", comment); +#ifndef SSH_X509STORE_DISABLED + } +#endif /*ndef SSH_X509STORE_DISABLED*/ } key_free(key); xfree(comment); @@ -317,6 +332,7 @@ seed_rng(); SSLeay_add_all_algorithms(); + fill_default_xkalg(); /* At first, get a connection to the authentication agent. */ ac = ssh_get_authentication_connection(); diff -ruN openssh-4.2p1/ssh-agent.0 openssh-4.2p1+x509-5.5/ssh-agent.0 --- openssh-4.2p1/ssh-agent.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-agent.0 2006-04-26 00:05:18.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-AGENT(1) OpenBSD Reference Manual SSH-AGENT(1) +SSH-AGENT(1) System General Commands Manual SSH-AGENT(1) NAME ssh-agent - authentication agent @@ -9,7 +9,8 @@ DESCRIPTION ssh-agent is a program to hold private keys used for public key authenti- - cation (RSA, DSA). The idea is that ssh-agent is started in the begin- + cation (RSA, DSA). It is possible to contain in addition corresponding + X.509 certificate. The idea is that ssh-agent is started in the begin- ning of an X-session or a login session, and all other windows or pro- grams are started as clients to the ssh-agent program. Through use of environment variables the agent can be located and automatically used for @@ -18,8 +19,8 @@ The options are as follows: -a bind_address - Bind the agent to the unix-domain socket bind_address. The de- - fault is /tmp/ssh-XXXXXXXX/agent.. + Bind the agent to the unix-domain socket bind_address. The + default is /tmp/ssh-XXXXXXXXXX/agent.. -c Generate C-shell commands on stdout. This is the default if SHELL looks like it's a csh style of shell. @@ -33,9 +34,9 @@ -t life Set a default value for the maximum lifetime of identities added to the agent. The lifetime may be specified in seconds or in a - time format specified in sshd(8). A lifetime specified for an - identity with ssh-add(1) overrides this value. Without this op- - tion the default maximum lifetime is forever. + time format specified in sshd_config(5). A lifetime specified + for an identity with ssh-add(1) overrides this value. Without + this option the default maximum lifetime is forever. -d Debug mode. When this option is specified ssh-agent will not fork. @@ -48,9 +49,10 @@ ~/.ssh/id_rsa, ~/.ssh/id_dsa and ~/.ssh/identity. If the identity has a passphrase, ssh-add(1) asks for the passphrase (using a small X11 appli- cation if running under X11, or from the terminal if running without X). - It then sends the identity to the agent. Several identities can be - stored in the agent; the agent can automatically use any of these identi- - ties. ssh-add -l displays the identities currently held by the agent. + It then sends the identity to the agent. Identity can by X.509 certifi- + cate that match private key. Several identities can be stored in the + agent; the agent can automatically use any of these identities. ssh-add + -l displays the identities currently held by the agent. The idea is that the agent is run in the user's local PC, laptop, or ter- minal. Authentication data need not be stored on any other machine, and @@ -70,15 +72,15 @@ Later ssh(1) looks at these variables and uses them to establish a con- nection to the agent. - The agent will never send a private key over its request channel. In- - stead, operations that require a private key will be performed by the + The agent will never send a private key over its request channel. + Instead, operations that require a private key will be performed by the agent, and the result will be returned to the requester. This way, pri- vate keys are not exposed to clients using the agent. A unix-domain socket is created and the name of this socket is stored in the SSH_AUTH_SOCK environment variable. The socket is made accessible - only to the current user. This method is easily abused by root or anoth- - er instance of the same user. + only to the current user. This method is easily abused by root or + another instance of the same user. The SSH_AGENT_PID environment variable holds the agent's process ID. @@ -92,13 +94,15 @@ ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of - the user. + the user. It is possible to contain private key followed by + X.509 certificate that match it. ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of - the user. + the user. It is possible to contain private key followed by + X.509 certificate that match it. - /tmp/ssh-XXXXXXXX/agent. + /tmp/ssh-XXXXXXXXXX/agent. Unix-domain sockets used to contain the connection to the authen- tication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the @@ -112,6 +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. + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- + tificates. -OpenBSD 3.8 September 25, 1999 2 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/ssh-agent.1 openssh-4.2p1+x509-5.5/ssh-agent.1 --- openssh-4.2p1/ssh-agent.1 2005-05-26 05:04:02.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-agent.1 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.42 2005/04/21 06:17:50 djm Exp $ +.\" $OpenBSD$ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -13,6 +13,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -54,6 +55,7 @@ .Nm is a program to hold private keys used for public key authentication (RSA, DSA). +It is possible to contain in addition corresponding X.509 certificate. The idea is that .Nm is started in the beginning of an X-session or a login session, and @@ -70,7 +72,7 @@ Bind the agent to the unix-domain socket .Ar bind_address . The default is -.Pa /tmp/ssh-XXXXXXXX/agent. . +.Pa /tmp/ssh-XXXXXXXXXX/agent. . .It Fl c Generate C-shell commands on .Dv stdout . @@ -90,7 +92,7 @@ .It Fl t Ar life Set a default value for the maximum lifetime of identities added to the agent. The lifetime may be specified in seconds or in a time format specified in -.Xr sshd 8 . +.Xr sshd_config 5 . A lifetime specified for an identity with .Xr ssh-add 1 overrides this value. @@ -120,6 +122,7 @@ asks for the passphrase (using a small X11 application if running under X11, or from the terminal if running without X). It then sends the identity to the agent. +Identity can by X.509 certificate that match private key. Several identities can be stored in the agent; the agent can automatically use any of these identities. .Ic ssh-add -l @@ -183,9 +186,13 @@ Contains the protocol version 1 RSA authentication identity of the user. .It Pa ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of the user. +It is possible to contain private key +followed by X.509 certificate that match it. .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. -.It Pa /tmp/ssh-XXXXXXXX/agent. +It is possible to contain private key +followed by X.509 certificate that match it. +.It Pa /tmp/ssh-XXXXXXXXXX/agent. Unix-domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. @@ -205,3 +212,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/ssh-agent.c openssh-4.2p1+x509-5.5/ssh-agent.c --- openssh-4.2p1/ssh-agent.c 2004-11-05 11:38:03.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-agent.c 2006-05-19 09:06:01.000000000 +0300 @@ -11,6 +11,8 @@ * called by a name other than "ssh" or "Secure Shell". * * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * X.509 certificates support, + * 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 @@ -35,7 +37,7 @@ #include "includes.h" #include "openbsd-compat/sys-queue.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.122 2004/10/29 22:53:56 djm Exp $"); +RCSID("$OpenBSD$"); #include #include @@ -50,6 +52,8 @@ #include "authfd.h" #include "compat.h" #include "log.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" #include "misc.h" #ifdef SMARTCARD @@ -150,6 +154,25 @@ xfree(id); } +static int/*bool*/ +key_match(const Key *key, Key *found) { + int kt, ret; + + if (key->type == found->type) + return(key_equal(key, found)); + + kt = found->type; + switch(found->type) { + case KEY_X509_RSA: found->type = KEY_RSA; break; + case KEY_X509_DSA: found->type = KEY_DSA; break; + default: return(0); + } + + ret = key_equal(key, found); + found->type = kt; + return(ret); +} + /* return matching private key for given public key */ static Identity * lookup_identity(Key *key, int version) @@ -158,7 +181,7 @@ Idtab *tab = idtab_lookup(version); TAILQ_FOREACH(id, &tab->idlist, next) { - if (key_equal(key, id->key)) + if (key_match(key, id->key)) return (id); } return (NULL); @@ -303,8 +326,12 @@ key = key_from_blob(blob, blen); if (key != NULL) { Identity *id = lookup_identity(key, 2); - if (id != NULL && (!id->confirm || confirm_key(id) == 0)) + if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { + int kt = id->key->type; + id->key->type = key->type; ok = key_sign(id->key, &signature, &slen, data, dlen); + id->key->type = kt; + } } key_free(key); buffer_init(&msg); @@ -449,6 +476,7 @@ xfree(type_name); switch (type) { case KEY_DSA: + case KEY_X509_DSA: k = key_new_private(type); buffer_get_bignum2(&e->request, k->dsa->p); buffer_get_bignum2(&e->request, k->dsa->q); @@ -457,6 +485,7 @@ buffer_get_bignum2(&e->request, k->dsa->priv_key); break; case KEY_RSA: + case KEY_X509_RSA: k = key_new_private(type); buffer_get_bignum2(&e->request, k->rsa->n); buffer_get_bignum2(&e->request, k->rsa->e); @@ -472,10 +501,29 @@ buffer_clear(&e->request); goto send; } + switch (type) { + case KEY_X509_RSA: + case KEY_X509_DSA: { + u_char *blob = NULL; + u_int blen = 0; + Key *key = NULL; + + blob = buffer_get_string(&e->request, &blen); + key = x509key_from_blob(blob, blen); + if(key == NULL) { + fatal("process_add_identity() x509key_from_blob fail"); + } + k->x509 = key->x509; + key->x509 = NULL; + key_free(key); + } + break; + } break; } /* enable blinding */ switch (k->type) { + case KEY_X509_RSA: case KEY_RSA: case KEY_RSA1: if (RSA_blinding_on(k->rsa, NULL) != 1) { @@ -1018,6 +1066,7 @@ #endif SSLeay_add_all_algorithms(); + fill_default_xkalg(); __progname = ssh_get_progname(av[0]); init_rng(); diff -ruN openssh-4.2p1/ssh.c openssh-4.2p1+x509-5.5/ssh.c --- openssh-4.2p1/ssh.c 2005-08-12 15:10:56.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh.c 2005-09-02 09:06:01.000000000 +0300 @@ -18,6 +18,9 @@ * Modified to work with SSL by Niels Provos * in Canada (German citizen). * + * 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: @@ -40,10 +43,14 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.249 2005/07/30 01:26:16 djm Exp $"); +RCSID("$OpenBSD$"); #include #include +#ifdef LDAP_ENABLED +/* OpenSSL extension defined in x509_by_ldap.c */ +extern void ERR_load_X509byLDAP_strings(void); +#endif #include "ssh.h" #include "ssh1.h" @@ -79,6 +86,9 @@ extern char *__progname; +/* ssh-x509.c needs this */ +extern int (*pssh_x509cert_check)(X509 *cert); + /* Flag indicating whether debug mode is on. This can be set on the command line. */ int debug_flag = 0; @@ -190,6 +200,7 @@ __progname = ssh_get_progname(av[0]); init_rng(); + pssh_x509cert_check = ssh_x509cert_check; /* * Save the original real uid. It will be needed later (uid-swapping @@ -515,6 +526,9 @@ SSLeay_add_all_algorithms(); ERR_load_crypto_strings(); +#ifdef LDAP_ENABLED + ERR_load_X509byLDAP_strings(); +#endif /* Initialize the command to execute on remote host. */ buffer_init(&command); diff -ruN openssh-4.2p1/ssh_config openssh-4.2p1+x509-5.5/ssh_config --- openssh-4.2p1/ssh_config 2005-02-09 00:46:48.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh_config 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -# $OpenBSD: ssh_config,v 1.20 2005/01/28 09:45:53 dtucker Exp $ +# $OpenBSD$ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for @@ -37,3 +37,14 @@ # Cipher 3des # Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc # EscapeChar ~ +# AllowedCertPurpose sslserver +# MandatoryCRL no +# CACertificateFile /etc/ssh/ca/ca-bundle.crt +# CACertificatePath /etc/ssh/ca/crt +# CARevocationFile /etc/ssh/ca/ca-bundle.crl +# CARevocationPath /etc/ssh/ca/crl +# UserCACertificateFile ~/.ssh/ca-bundle.crt +# UserCACertificatePath ~/.ssh/crt +# UserCARevocationFile ~/.ssh/ca-bundle.crl +# UserCARevocationPath ~/.ssh/crl +# VAType none diff -ruN openssh-4.2p1/ssh_config.0 openssh-4.2p1+x509-5.5/ssh_config.0 --- openssh-4.2p1/ssh_config.0 2005-09-01 12:15:26.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh_config.0 2006-05-19 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -SSH_CONFIG(5) OpenBSD Programmer's Manual SSH_CONFIG(5) +SSH_CONFIG(5) System File Formats Manual SSH_CONFIG(5) NAME ssh_config - OpenSSH SSH client configuration files @@ -46,10 +46,19 @@ canonicalized host name before matching). AddressFamily - Specifies which address family to use when connecting. Valid ar- - guments are ``any'', ``inet'' (use IPv4 only) or ``inet6'' (use + Specifies which address family to use when connecting. Valid + arguments are ``any'', ``inet'' (use IPv4 only) or ``inet6'' (use IPv6 only). + AllowedCertPurpose + 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' ; + o `any' , `Any Purpose' , `Any_Purpose' or `AnyPurpose' ; + o `skip' or `' (empty): do not check purpose. + The default is ``sslserver''. + BatchMode If set to ``yes'', passphrase/password querying will be disabled. This option is useful in scripts and other batch jobs where no @@ -57,11 +66,45 @@ ``yes'' or ``no''. The default is ``no''. BindAddress - Use the specified address on the local machine as the source ad- - dress of the connection. Only useful on systems with more than + Use the specified address on the local machine as the source + address of the connection. Only useful on systems with more than one address. Note that this option does not work if UsePrivilegedPort is set to ``yes''. + CACertificateFile + ``X509 store'' option: This file contain multiple certificates of + certificate signers in PEM format concatenated together. The + default is /etc/ssh/ca/ca-bundle.crt. + + CACertificatePath + ``X509 store'' option: ``Hash dir'' with certificates of certifi- + cate signers. Each certificate should be stored in separate file + with name [HASH].[NUMBER], where [HASH] is certificate hash value + and [NUMBER] is an integer starting from zero. The default is + /etc/ssh/ca/crt. + + CAldapVersion + ``X509 store'' option: Specifies LDAP protocol version. The + default depend from LDAP library. + + CAldapURL + ``X509 store'' option: Specifies hostport and dn of LDAP URLs + (Uniform Resource Locators) as detailed in RFC 2255. The rest of + URL is build internally. Because of OpenSSH options parser limi- + tation use `%3D' instead of `=' ! + + CARevocationFile + ``X509 store'' option: This file contain multiple ``Certificate + Revocation List'' (CRL) of certificate signers in PEM format con- + catenated together. The default is /etc/ssh/ca/ca-bundle.crl. + + CARevocationPath + ``X509 store'' option: ``Hash dir'' with ``Certificate Revocation + List'' (CRL) of certificate signers. Each CRL should be stored in + separate file with name [HASH].r[NUMBER], where [HASH] is CRL + hash value and [NUMBER] is an integer starting from zero. The + default is /etc/ssh/ca/crl. + ChallengeResponseAuthentication Specifies whether to use challenge response authentication. The argument to this keyword must be ``yes'' or ``no''. The default @@ -69,17 +112,17 @@ CheckHostIP If this flag is set to ``yes'', ssh will additionally check the - host IP address in the known_hosts file. This allows ssh to de- - tect if a host key changed due to DNS spoofing. If the option is - set to ``no'', the check will not be executed. The default is + host IP address in the known_hosts file. This allows ssh to + detect if a host key changed due to DNS spoofing. If the option + is set to ``no'', the check will not be executed. The default is ``yes''. Cipher Specifies the cipher to use for encrypting the session in proto- col version 1. Currently, ``blowfish'', ``3des'', and ``des'' - are supported. des is only supported in the ssh client for in- - teroperability with legacy protocol 1 implementations that do not - support the 3des cipher. Its use is strongly discouraged due to - cryptographic weaknesses. The default is ``3des''. + are supported. des is only supported in the ssh client for + interoperability with legacy protocol 1 implementations that do + not support the 3des cipher. Its use is strongly discouraged due + to cryptographic weaknesses. The default is ``3des''. Ciphers Specifies the ciphers allowed for protocol version 2 in order of @@ -113,15 +156,15 @@ option applies to protocol version 1 only. ConnectionAttempts - Specifies the number of tries (one per second) to make before ex- - iting. The argument must be an integer. This may be useful in + Specifies the number of tries (one per second) to make before + exiting. The argument must be an integer. This may be useful in scripts if the connection sometimes fails. The default is 1. ConnectTimeout Specifies the timeout (in seconds) used when connecting to the ssh server, instead of using the default system TCP timeout. - This value is used only when the target is down or really un- - reachable, not when it refuses the connection. + This value is used only when the target is down or really + unreachable, not when it refuses the connection. ControlMaster Enables the sharing of multiple sessions over a single network @@ -132,10 +175,10 @@ These sessions will reuse the master instance's network connec- tion rather than initiating new ones. Setting this to ``ask'' will cause ssh to listen for control connections, but require - confirmation using the SSH_ASKPASS program before they are ac- - cepted (see ssh-add(1) for details). If the ControlPath can not - be opened, ssh will continue without connecting to a master in- - stance. + confirmation using the SSH_ASKPASS program before they are + accepted (see ssh-add(1) for details). If the ControlPath can + not be opened, ssh will continue without connecting to a master + instance. X11 and ssh-agent(1) forwarding is supported over these multi- plexed connections, however the display and agent fowarded will @@ -163,9 +206,9 @@ over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. The argument must be a port number. Currently the SOCKS4 and - SOCKS5 protocols are supported, and ssh will act as a SOCKS serv- - er. Multiple forwardings may be specified, and additional for- - wardings can be given on the command line. Only the superuser + SOCKS5 protocols are supported, and ssh will act as a SOCKS + server. Multiple forwardings may be specified, and additional + forwardings can be given on the command line. Only the superuser can forward privileged ports. EnableSSHKeysign @@ -197,9 +240,9 @@ the agent. ForwardX11 - Specifies whether X11 connections will be automatically redirect- - ed over the secure channel and DISPLAY set. The argument must be - ``yes'' or ``no''. The default is ``no''. + Specifies whether X11 connections will be automatically redi- + rected over the secure channel and DISPLAY set. The argument + must be ``yes'' or ``no''. The default is ``no''. X11 forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the @@ -229,9 +272,10 @@ forwarded ports. By default, ssh binds local port forwardings to the loopback address. This prevents other remote hosts from con- necting to forwarded ports. GatewayPorts can be used to specify - that ssh should bind local port forwardings to the wildcard ad- - dress, thus allowing remote hosts to connect to forwarded ports. - The argument must be ``yes'' or ``no''. The default is ``no''. + that ssh should bind local port forwardings to the wildcard + address, thus allowing remote hosts to connect to forwarded + ports. The argument must be ``yes'' or ``no''. The default is + ``no''. GlobalKnownHostsFile Specifies a file to use for the global host key database instead @@ -244,14 +288,14 @@ GSSAPIDelegateCredentials Forward (delegate) credentials to the server. The default is - ``no''. Note that this option applies to protocol version 2 on- - ly. + ``no''. Note that this option applies to protocol version 2 + only. HashKnownHosts Indicates that ssh should hash host names and addresses when they are added to ~/.ssh/known_hosts. These hashed names may be used - normally by ssh and sshd, but they do not reveal identifying in- - formation should the file's contents be disclosed. The default + normally by ssh and sshd, but they do not reveal identifying + information should the file's contents be disclosed. The default is ``no''. Note that hashing of names and addresses will not be retrospectively applied to existing known hosts files, but these may be manually hashed using ssh-keygen(1). @@ -259,13 +303,15 @@ HostbasedAuthentication Specifies whether to try rhosts based authentication with public key authentication. The argument must be ``yes'' or ``no''. The - default is ``no''. This option applies to protocol version 2 on- - ly and is similar to RhostsRSAAuthentication. + default is ``no''. This option applies to protocol version 2 + only and is similar to RhostsRSAAuthentication. HostKeyAlgorithms Specifies the protocol version 2 host key algorithms that the client wants to use in order of preference. The default for this - option is: ``ssh-rsa,ssh-dss''. + option depend from X509KeyAlgorithm. It contain first specified + X509KeyAlgorithm for RSA key, followed by first specified + X509KeyAlgorithm for DSA key, followed by ``,ssh-rsa,ssh-dss''. HostKeyAlias Specifies an alias that should be used instead of the real host @@ -284,11 +330,13 @@ Specifies a file from which the user's RSA or DSA authentication identity is read. The default is ~/.ssh/identity for protocol version 1, and ~/.ssh/id_rsa and ~/.ssh/id_dsa for protocol ver- - sion 2. Additionally, any identities represented by the authen- - tication agent will be used for authentication. The file name - may use the tilde syntax to refer to a user's home directory. It - is possible to have multiple identity files specified in configu- - ration files; all these identities will be tried in sequence. + sion 2. For version 2 is possible identity file to contain key + followed by X.509 certificate that match the key. Additionally, + any identities represented by the authentication agent will be + used for authentication. The file name may use the tilde syntax + to refer to a user's home directory. It is possible to have mul- + tiple identity files specified in configuration files; all these + identities will be tried in sequence. IdentitiesOnly Specifies that ssh should only use the authentication identity @@ -299,8 +347,8 @@ ``no''. KbdInteractiveDevices - Specifies the list of methods to use in keyboard-interactive au- - thentication. Multiple method names must be comma-separated. + Specifies the list of methods to use in keyboard-interactive + authentication. Multiple method names must be comma-separated. The default is to use the server specified list. LocalForward @@ -327,20 +375,25 @@ DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of verbose output. - MACs Specifies the MAC (message authentication code) algorithms in or- - der of preference. The MAC algorithm is used in protocol version - 2 for data integrity protection. Multiple algorithms must be - comma-separated. The default is ``hmac-md5,hmac-sha1,hmac- - ripemd160,hmac-sha1-96,hmac-md5-96''. + MACs Specifies the MAC (message authentication code) algorithms in + order of preference. The MAC algorithm is used in protocol ver- + sion 2 for data integrity protection. Multiple algorithms must + be comma-separated. The default is + ``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96''. + + MandatoryCRL + ``X509 store'' option: Specifies whether CRL must present in + store for all certificates in ``certificate chain'' with atribute + ``X509v3 CRL Distribution Points''. The default is ``no''. NoHostAuthenticationForLocalhost This option can be used if the home directory is shared across - machines. In this case localhost will refer to a different ma- - chine on each of the machines and the user will get many warnings - about changed host keys. However, this option disables host au- - thentication for localhost. The argument to this keyword must be - ``yes'' or ``no''. The default is to check the host key for lo- - calhost. + machines. In this case localhost will refer to a different + machine on each of the machines and the user will get many warn- + ings about changed host keys. However, this option disables host + authentication for localhost. The argument to this keyword must + be ``yes'' or ``no''. The default is to check the host key for + localhost. NumberOfPasswordPrompts Specifies the number of password prompts before giving up. The @@ -355,11 +408,11 @@ is 22. PreferredAuthentications - Specifies the order in which the client should try protocol 2 au- - thentication methods. This allows a client to prefer one method - (e.g. keyboard-interactive) over another method (e.g. password) - The default for this option is: ``hostbased,publickey,keyboard- - interactive,password''. + Specifies the order in which the client should try protocol 2 + authentication methods. This allows a client to prefer one + method (e.g. keyboard-interactive) over another method (e.g. + password) The default for this option is: + ``hostbased,publickey,keyboard-interactive,password''. Protocol Specifies the protocol versions ssh should support in order of @@ -377,10 +430,10 @@ write to its standard output. It should eventually connect an sshd(8) server running on some machine, or execute sshd -i some- where. Host key management will be done using the HostName of - the host being connected (defaulting to the name typed by the us- - er). Setting the command to ``none'' disables this option en- - tirely. Note that CheckHostIP is not available for connects with - a proxy command. + the host being connected (defaulting to the name typed by the + user). Setting the command to ``none'' disables this option + entirely. Note that CheckHostIP is not available for connects + with a proxy command. This directive is useful in conjunction with nc(1) and its proxy support. For example, the following directive would connect via @@ -388,6 +441,16 @@ ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p + PubkeyAlgorithms + Specifies the protocol version 2 algorithms used in ``publickey'' + authentication allowed to sent to the host. The default is all + supported by client and depend from X509KeyAlgorithm, i.e. the + option allow all specified by X509KeyAlgorithm plus ``ssh-rsa'' + and ``ssh-dss''. If a X.509 certificate is used as identity but + corresponding algorithm is not allowed the client will try algo- + rithm ( ``ssh-rsa'' or ``ssh-dss'' ) conforming to certificate + public key if allowed. + PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be ``yes'' or ``no''. The default is @@ -455,9 +518,9 @@ tion has become inactive. The default value is 3. If, for example, ServerAliveInterval - (above) is set to 15, and ServerAliveCountMax is left at the de- - fault, if the server becomes unresponsive ssh will disconnect af- - ter approximately 45 seconds. + (above) is set to 15, and ServerAliveCountMax is left at the + default, if the server becomes unresponsive ssh will disconnect + after approximately 45 seconds. SmartcardDevice Specifies which smartcard device to use. The argument to this @@ -508,21 +571,84 @@ trouble of having to remember to give the user name on the com- mand line. + UserCACertificateFile + ``X509 store'' option: User CACertificateFile , the default is + ~/.ssh/ca-bundle.crt. + + UserCACertificatePath + ``X509 store'' option: User CACertificatePath , the default is + ~/.ssh/crt. + + UserCAldapVersion + ``X509 store'' option: User CAldapVersion. + + UserCAldapURL + ``X509 store'' option: User CAldapURL. + + UserCARevocationFile + ``X509 store'' option: User CARevocationFile , the default is + ~/.ssh/ca-bundle.crl. + + UserCARevocationPath + ``X509 store'' option: User CARevocationPath , the default is + ~/.ssh/crl. + UserKnownHostsFile Specifies a file to use for the user host key database instead of ~/.ssh/known_hosts. + VACertificateFile + File with X.509 certificates in PEM format concatenated together. + In use when VAType is set to ``ocspspec''. The default value is + `' (empty). Certificates from that file explicitly trust `OCSP + Responder' public key. They are used as trusted certificates in + addition to certificates from CACertificateFile , + CACertificatePath , UserCACertificateFile and + UserCACertificatePath to verify responder certificate. + + VAType Specifies whether `Online Certificate Status Protocol' (OCSP) is + used to validate X.509 certificates. Accepted values are case + insensitive: + o `none' : do not use OCSP to validate certificates; + o `ocspcert' : validate only certificates that specify `OCSP + Service Locator' URL; + o `ocspspec' : use specified in the configuration `OCSP + Responder' to validate all certificates. + The default is ``none''. + + VAOCSPResponderURL + `Access Location' / `OCSP Service Locator' URL of the OCSP + 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. + + X509KeyAlgorithm + Specifies how X.509 certificates and signatures are used for pro- + tocol version 2. It is possible to have multiple algorithms in + form specified in X509 Key Algorithms Format. sshd use the first + listed for ``rsa'' or ``dsa'' key in signing and accept all + listed. + + The default for certificates with RSA key is: + X509KeyAlgorithm x509v3-sign-rsa,rsa-md5 + X509KeyAlgorithm x509v3-sign-rsa,rsa-sha1 + + The default for certificates with DSA key is: + X509KeyAlgorithm x509v3-sign-dss,dss-asn1 + X509KeyAlgorithm x509v3-sign-dss,dss-raw + + X509rsaSigType + Deprecated option replaced by X509KeyAlgorithm. XAuthLocation Specifies the full pathname of the xauth(1) program. The default @@ -531,9 +657,10 @@ FILES ~/.ssh/config This is the per-user configuration file. The format of this file - is described above. This file is used by the ssh client. Be- - cause of the potential for abuse, this file must have strict per- - missions: read/write for the user, and not accessible by others. + is described above. This file is used by the ssh client. + Because of the potential for abuse, this file must have strict + permissions: read/write for the user, and not accessible by oth- + ers. /etc/ssh/ssh_config Systemwide configuration file. This file provides defaults for @@ -549,6 +676,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. + versions 1.5 and 2.0. Roumen Petrov contributed support for X.509 cer- + tificates. -OpenBSD 3.8 September 25, 1999 9 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/ssh_config.5 openssh-4.2p1+x509-5.5/ssh_config.5 --- openssh-4.2p1/ssh_config.5 2005-07-14 10:06:51.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh_config.5 2006-05-19 09:06:00.000000000 +0300 @@ -13,6 +13,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002-2006 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -34,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.61 2005/07/08 12:53:10 jmc Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSH_CONFIG 5 .Os @@ -123,6 +124,38 @@ (use IPv4 only) or .Dq inet6 (use IPv6 only). +.It Cm AllowedCertPurpose +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 +.It +.Sq sslserver +, +.Sq SSL server +, +.Sq SSL_server +or +.Sq server +; +.It +.Sq any +, +.Sq Any Purpose +, +.Sq Any_Purpose +or +.Sq AnyPurpose +; +.It +.Sq skip +or +.Sq +.. +(empty): do not check purpose. +.El +The default is +.Dq sslserver . .It Cm BatchMode If set to .Dq yes , @@ -143,6 +176,54 @@ .Cm UsePrivilegedPort is set to .Dq yes . +.It Cm CACertificateFile +.Dq X509 store +option: +This file contain multiple certificates of certificate signers in +PEM format concatenated together. The default is +.Pa /etc/ssh/ca/ca-bundle.crt . +.It Cm CACertificatePath +.Dq X509 store +option: +.Dq "Hash dir" +with certificates of certificate signers. Each certificate should be +stored in separate file with name [HASH].[NUMBER], where [HASH] is +certificate hash value and [NUMBER] is an integer starting from zero. +The default is +.Pa /etc/ssh/ca/crt . +.It Cm CAldapVersion +.Dq X509 store +option: +Specifies LDAP protocol version. +The default depend from LDAP library. +.It Cm CAldapURL +.Dq X509 store +option: +Specifies hostport and dn of LDAP URLs (Uniform Resource Locators) +as detailed in RFC 2255. The rest of URL is build internally. +Because of OpenSSH options parser limitation use +.Sq %3D +instead of +.Sq = +! +.It Cm CARevocationFile +.Dq X509 store +option: +This file contain multiple +.Dq "Certificate Revocation List" +(CRL) of certificate signers in PEM format concatenated together. +The default is +.Pa /etc/ssh/ca/ca-bundle.crl . +.It Cm CARevocationPath +.Dq X509 store +option: +.Dq "Hash dir" +with +.Dq "Certificate Revocation List" +(CRL) of certificate signers. Each CRL should be stored in separate +file with name [HASH].r[NUMBER], where [HASH] is CRL hash value and +[NUMBER] is an integer starting from zero. The default is +.Pa /etc/ssh/ca/crl . .It Cm ChallengeResponseAuthentication Specifies whether to use challenge response authentication. The argument to this keyword must be @@ -478,8 +559,12 @@ .It Cm HostKeyAlgorithms Specifies the protocol version 2 host key algorithms that the client wants to use in order of preference. -The default for this option is: -.Dq ssh-rsa,ssh-dss . +The default for this option depend from +.Cm X509KeyAlgorithm . +It contain first specified X509KeyAlgorithm for RSA key, +followed by first specified X509KeyAlgorithm for DSA key, +followed by +.Dq ,ssh-rsa,ssh-dss . .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key @@ -503,6 +588,8 @@ and .Pa ~/.ssh/id_dsa for protocol version 2. +For version 2 is possible identity file to contain key +followed by X.509 certificate that match the key. Additionally, any identities represented by the authentication agent will be used for authentication. The file name may use the tilde @@ -579,6 +666,15 @@ Multiple algorithms must be comma-separated. The default is .Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 . +.It Cm MandatoryCRL +.Dq X509 store +option: +Specifies whether CRL must present in store for all certificates in +.Dq certificate chain +with atribute +.Dq X509v3 CRL Distribution Points . +The default is +.Dq no . .It Cm NoHostAuthenticationForLocalhost This option can be used if the home directory is shared across machines. In this case localhost will refer to a different machine on each of @@ -664,6 +760,25 @@ .Bd -literal -offset 3n ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p .Ed +.It Cm PubkeyAlgorithms +Specifies the protocol version 2 algorithms used in +.Dq publickey +authentication allowed to sent to the host. +The default is all supported by client and depend from +.Cm X509KeyAlgorithm , +i.e. the option allow all specified by +.Cm X509KeyAlgorithm +plus +.Dq ssh-rsa +and +.Dq ssh-dss . +If a X.509 certificate is used as identity +but corresponding algorithm is not allowed +the client will try algorithm ( +.Dq ssh-rsa +or +.Dq ssh-dss +) conforming to certificate public key if allowed. .It Cm PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be @@ -868,12 +983,102 @@ This can be useful when a different user name is used on different machines. This saves the trouble of having to remember to give the user name on the command line. +.It Cm UserCACertificateFile +.Dq X509 store +option: +User +.Cm CACertificateFile +, the default is +.Pa ~/.ssh/ca-bundle.crt . +.It Cm UserCACertificatePath +.Dq X509 store +option: +User +.Cm CACertificatePath +, the default is +.Pa ~/.ssh/crt . +.It Cm UserCAldapVersion +.Dq X509 store +option: +User +.Cm CAldapVersion . +.It Cm UserCAldapURL +.Dq X509 store +option: +User +.Cm CAldapURL . +.It Cm UserCARevocationFile +.Dq X509 store +option: +User +.Cm CARevocationFile +, the default is +.Pa ~/.ssh/ca-bundle.crl . +.It Cm UserCARevocationPath +.Dq X509 store +option: +User +.Cm CARevocationPath +, the default is +.Pa ~/.ssh/crl . .It Cm UserKnownHostsFile Specifies a file to use for the user host key database instead of .Pa ~/.ssh/known_hosts . +.It Cm VACertificateFile +File with X.509 certificates in PEM format concatenated together. +In use when +.Cm VAType +is set to +.Dq ocspspec . +The default value is +.Sq +.. +(empty). +Certificates from that file explicitly trust +.Sq "OCSP Responder" +public key. +They are used as trusted certificates in addition to certificates from +.Cm CACertificateFile +, +.Cm CACertificatePath +, +.Cm UserCACertificateFile +and +.Cm UserCACertificatePath +to verify responder certificate. +.It Cm VAType +Specifies whether +.Sq "Online Certificate Status Protocol" +(OCSP) is used to validate X.509 certificates. +Accepted values are case insensitive: +.Bl -bullet -compact +.It +.Sq none +: do not use OCSP to validate certificates; +.It +.Sq ocspcert +: validate only certificates that specify +.Sq "OCSP Service Locator" +URL; +.It +.Sq ocspspec +: use specified in the configuration +.Sq "OCSP Responder" +to validate all certificates. +.El +The default is +.Dq none . +.It Cm VAOCSPResponderURL +.Sq "Access Location" +/ +.Sq "OCSP Service Locator" +URL of the OCSP provider. In use when +.Cm VAType +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 , @@ -895,6 +1100,48 @@ The default is .Dq no . Note that this option applies to protocol version 2 only. +.It Cm X509KeyAlgorithm +Specifies how X.509 certificates and signatures are used for protocol version 2. +It is possible to have multiple algorithms +in form specified in +.Sx X509 Key Algorithms Format . +.Nm sshd +use the first listed for +.Dq rsa +or +.Dq dsa +key in signing and +accept all listed. +.Pp +The default for certificates with RSA key is: +.Bl -item -offset indent -compact +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-rsa , Ar rsa-md5 +.Sm on +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-rsa , Ar rsa-sha1 +.Sm on +.El +.Pp +The default for certificates with DSA key is: +.Bl -item -offset indent -compact +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-dss , Ar dss-asn1 +.Sm on +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-dss , Ar dss-raw +.Sm on +.El +.It Cm X509rsaSigType +Deprecated option replaced by X509KeyAlgorithm. .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 @@ -930,3 +1177,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/sshconnect2.c openssh-4.2p1+x509-5.5/sshconnect2.c --- openssh-4.2p1/sshconnect2.c 2005-08-31 12:46:27.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshconnect2.c 2006-05-19 09:06:01.000000000 +0300 @@ -1,5 +1,6 @@ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 2006 Roumen Petrov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.142 2005/08/30 22:08:05 djm Exp $"); +RCSID("$OpenBSD$"); #include "openbsd-compat/sys-queue.h" @@ -839,6 +840,7 @@ /* load the private key from the file */ if ((prv = load_identity_file(id->filename)) == NULL) return (-1); + prv->type = id->key->type; ret = key_sign(prv, sigp, lenp, data, datalen); key_free(prv); return (ret); @@ -1012,6 +1014,7 @@ char *comment; int i, found; + debug2("preparing keys"); TAILQ_INIT(&agent); /* keys from the agent */ TAILQ_INIT(&files); /* keys from the config file */ preferred = &authctxt->keys; @@ -1091,11 +1094,70 @@ } } +static int +get_allowed_keytype(int type) { + static int allowed[KEY_UNSPEC] = { 0 }; + int pktype; + + switch(type) { + case KEY_RSA: + case KEY_DSA: + case KEY_X509_RSA: + case KEY_X509_DSA: + break; + default: + return(KEY_UNSPEC); + } + + if (options.pubkey_algorithms == NULL) return(type); + + if (allowed[KEY_UNSPEC] != 1) { + /* prepare allowed key-types flags */ + char *s, *cp, *p; + memset(allowed, 0, sizeof(allowed)); + s = cp = xstrdup(options.pubkey_algorithms); + for (p = strsep(&cp, ","); + p && *p != '\0'; + p = strsep(&cp, ",") + ) { + pktype = key_type_from_name(p); + allowed[pktype] = 1; + } + xfree(s); + allowed[KEY_UNSPEC] = 1; + } + + if (allowed[type]) return(type); + + switch(type) { + case KEY_X509_RSA: type = KEY_RSA; break; + case KEY_X509_DSA: type = KEY_DSA; break; + default: + return(KEY_UNSPEC); + } + + return(allowed[type] ? type : KEY_UNSPEC); +} + +static void +set_keytype(Key *k, int kt) { + const char *n1, *n2; + + if (k->type == kt) return; + + /* key_ssh_name return pointers to statics */ + n1 = key_ssh_name(k); + k->type = kt; + n2 = key_ssh_name(k); + debug("Offering key-type '%s', original was '%s'", n2, n1); +} + int userauth_pubkey(Authctxt *authctxt) { Identity *id; int sent = 0; + int kt_sent; while ((id = TAILQ_FIRST(&authctxt->keys))) { if (id->tried++) @@ -1109,13 +1171,27 @@ * private key instead */ if (id->key && id->key->type != KEY_RSA1) { + kt_sent = get_allowed_keytype(id->key->type); + if (kt_sent == KEY_UNSPEC) { + logit("non-allowed public key: %s", id->filename); + continue; + } debug("Offering public key: %s", id->filename); + set_keytype(id->key, kt_sent); sent = send_pubkey_test(authctxt, id); } else if (id->key == NULL) { debug("Trying private key: %s", id->filename); id->key = load_identity_file(id->filename); if (id->key != NULL) { id->isprivate = 1; + kt_sent = get_allowed_keytype(id->key->type); + if (kt_sent == KEY_UNSPEC) { + logit("non-allowed private key: %s", id->filename); + key_free(id->key); + id->key = NULL; + continue; + } + set_keytype(id->key, kt_sent); sent = sign_and_send_pubkey(authctxt, id); key_free(id->key); id->key = NULL; diff -ruN openssh-4.2p1/sshconnect.c openssh-4.2p1+x509-5.5/sshconnect.c --- openssh-4.2p1/sshconnect.c 2005-07-17 10:22:46.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshconnect.c 2006-01-15 09:06:01.000000000 +0200 @@ -10,10 +10,33 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * X.509 certificates support, + * 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 + * 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" -RCSID("$OpenBSD: sshconnect.c,v 1.168 2005/07/17 07:17:55 djm Exp $"); +RCSID("$OpenBSD$"); #include @@ -31,6 +54,7 @@ #include "readconf.h" #include "atomicio.h" #include "misc.h" +#include "ssh-x509.h" #include "dns.h" @@ -534,6 +558,7 @@ char msg[1024]; int len, host_line, ip_line; const char *host_file = NULL, *ip_file = NULL; + char extramsg[1024], *subject = NULL; /* * Force accepting of the host key for loopback/localhost. The @@ -697,13 +722,27 @@ "No matching host key fingerprint" " found in DNS.\n"); } + if ((host_key->type == KEY_X509_RSA) || (host_key->type == KEY_X509_DSA)) { + subject = x509key_subject(host_key); + snprintf(extramsg, sizeof(extramsg), + "Distinguished name is %.*s.\n", + (int) X509_NAME_MAXLEN, subject); + } else { + subject = NULL; + *extramsg = '\0'; + } snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " "established%s\n" "%s key fingerprint is %s.\n%s" + "%s" "Are you sure you want to continue connecting " "(yes/no)? ", - host, ip, msg1, type, fp, msg2); + host, ip, msg1, type, fp, msg2, extramsg); + if(subject != NULL) { + xfree(subject); + subject = NULL; + } xfree(fp); if (!confirm(msg)) goto fail; @@ -743,7 +782,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) @@ -883,9 +922,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); } } } @@ -986,7 +1031,8 @@ static int show_other_keys(const char *host, Key *key) { - int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; + int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_X509_RSA, KEY_X509_DSA, -1}; + int i, found = 0; for (i = 0; type[i] != -1; i++) { @@ -1031,6 +1077,12 @@ error("It is also possible that the %s host key has just been changed.", type); error("The fingerprint for the %s key sent by the remote host is\n%s.", type, fp); + if ((host_key->type == KEY_X509_RSA) || (host_key->type == KEY_X509_DSA)) { + char *subject = x509key_subject(host_key); + error("Distinguished name sent by remote host is\n%.*s.", + (int) X509_NAME_MAXLEN, subject); + xfree(subject); + } error("Please contact your system administrator."); xfree(fp); diff -ruN openssh-4.2p1/sshd.0 openssh-4.2p1+x509-5.5/sshd.0 --- openssh-4.2p1/sshd.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd.0 2006-04-26 00:05:19.000000000 +0300 @@ -1,4 +1,4 @@ -SSHD(8) OpenBSD System Manager's Manual SSHD(8) +SSHD(8) System Manager's Manual SSHD(8) NAME sshd - OpenSSH SSH daemon @@ -14,8 +14,8 @@ intended to be as easy to install and use as possible. sshd is the daemon that listens for connections from clients. It is nor- - mally started at boot from /etc/rc. It forks a new daemon for each in- - coming connection. The forked daemons handle key exchange, encryption, + mally started at boot from /etc/rc. It forks a new daemon for each + incoming connection. The forked daemons handle key exchange, encryption, authentication, command execution, and data exchange. This implementa- tion of sshd supports both SSH protocol version 1 and 2 simultaneously. sshd works as follows: @@ -23,15 +23,15 @@ SSH protocol version 1 Each host has a host-specific RSA key (normally 2048 bits) used to iden- tify the host. Additionally, when the daemon starts, it generates a - server RSA key (normally 768 bits). This key is normally regenerated ev- - ery hour if it has been used, and is never stored on disk. + server RSA key (normally 768 bits). This key is normally regenerated + every hour if it has been used, and is never stored on disk. Whenever a client connects, the daemon responds with its public host and server keys. The client compares the RSA host key against its own database to verify that it has not changed. The client then generates a 256-bit random number. It encrypts this random number using both the - host key and the server key, and sends the encrypted number to the serv- - er. Both sides then use this random number as a session key which is + host key and the server key, and sends the encrypted number to the + server. Both sides then use this random number as a session key which is used to encrypt all further communications in the session. The rest of the session is encrypted using a conventional cipher, currently Blowfish or 3DES, with 3DES being used by default. The client selects the encryp- @@ -58,16 +58,18 @@ SSH protocol version 2 Version 2 works similarly: Each host has a host-specific key (RSA or DSA) - used to identify the host. However, when the daemon starts, it does not - generate a server key. Forward security is provided through a Diffie- - Hellman key agreement. This key agreement results in a shared session - key. + used to identify the host. It is possible host key to contain private + key followed by X.509 certificate that match it. However, when the dae- + mon starts, it does not generate a server key. Forward security is pro- + vided through a Diffie-Hellman key agreement. This key agreement results + in a shared session key. The rest of the session is encrypted using a symmetric cipher, currently 128-bit AES, Blowfish, 3DES, CAST128, Arcfour, 192-bit AES, or 256-bit - AES. The client selects the encryption algorithm to use from those of- - fered by the server. Additionally, session integrity is provided through - a cryptographic message authentication code (hmac-sha1 or hmac-md5). + AES. The client selects the encryption algorithm to use from those + offered by the server. Additionally, session integrity is provided + through a cryptographic message authentication code (hmac-sha1 or hmac- + md5). Protocol version 2 provides a public key based user (PubkeyAuthentica- tion) or client host (HostbasedAuthentication) authentication method, @@ -114,8 +116,8 @@ -d Debug mode. The server sends verbose debug output to the system log, and does not put itself in the background. The server also will not fork and will only process one connection. This option - is only intended for debugging for the server. Multiple -d op- - tions increase the debugging level. Maximum is 3. + is only intended for debugging for the server. Multiple -d + options increase the debugging level. Maximum is 3. -e When this option is specified, sshd will send the output to the standard error instead of the system log. @@ -126,10 +128,10 @@ figuration file. -g login_grace_time - Gives the grace time for clients to authenticate themselves (de- - fault 120 seconds). If the client fails to authenticate the user - within this many seconds, the server disconnects and exits. A - value of zero indicates no limit. + Gives the grace time for clients to authenticate themselves + (default 120 seconds). If the client fails to authenticate the + user within this many seconds, the server disconnects and exits. + A value of zero indicates no limit. -h host_key_file Specifies a file from which a host key is read. This option must @@ -138,14 +140,16 @@ /etc/ssh/ssh_host_key for protocol version 1, and /etc/ssh/ssh_host_rsa_key and /etc/ssh/ssh_host_dsa_key for pro- tocol version 2. It is possible to have multiple host key files - for the different protocol versions and host key algorithms. + for the different protocol versions and host key algorithms. It + is possible host key for protocol version 2 to contain private + key followed by X.509 certificate that match it. -i Specifies that sshd is being run from inetd(8). sshd is normally not run from inetd because it needs to generate the server key before it can respond to the client, and this may take tens of - seconds. Clients would have to wait too long if the key was re- - generated every time. However, with small key sizes (e.g., 512) - using sshd from inetd may be feasible. + seconds. Clients would have to wait too long if the key was + regenerated every time. However, with small key sizes (e.g., + 512) using sshd from inetd may be feasible. -k key_gen_time Specifies how often the ephemeral protocol version 1 server key @@ -153,14 +157,14 @@ tion for regenerating the key fairly often is that the key is not stored anywhere, and after about an hour it becomes impossible to recover the key for decrypting intercepted communications even if - the machine is cracked into or physically seized. A value of ze- - ro indicates that the key will never be regenerated. + the machine is cracked into or physically seized. A value of + zero indicates that the key will never be regenerated. -o option Can be used to give options in the format used in the configura- tion file. This is useful for specifying options for which there - is no separate command-line flag. For full details of the op- - tions, and their values, see sshd_config(5). + is no separate command-line flag. For full details of the + options, and their values, see sshd_config(5). -p port Specifies the port on which the server listens for connections @@ -168,8 +172,8 @@ fied in the configuration file are ignored when a command-line port is specified. - -q Quiet mode. Nothing is sent to the system log. Normally the be- - ginning, authentication, and termination of each connection is + -q Quiet mode. Nothing is sent to the system log. Normally the + beginning, authentication, and termination of each connection is logged. -t Test mode. Only check the validity of the configuration file and @@ -184,10 +188,10 @@ indicates that only dotted decimal addresses should be put into the utmp file. -u0 may also be used to prevent sshd from making DNS requests unless the authentication mechanism or configuration - requires it. Authentication mechanisms that may require DNS in- - clude RhostsRSAAuthentication, HostbasedAuthentication and using - a from="pattern-list" option in a key file. Configuration op- - tions that require DNS include using a USER@HOST pattern in + requires it. Authentication mechanisms that may require DNS + include RhostsRSAAuthentication, HostbasedAuthentication and + using a from="pattern-list" option in a key file. Configuration + options that require DNS include using a USER@HOST pattern in AllowUsers or DenyUsers. CONFIGURATION FILE @@ -227,7 +231,9 @@ ~/.ssh/authorized_keys is the default file that lists the public keys that are permitted for RSA authentication in protocol version 1 and for public key authentication (PubkeyAuthentication) in protocol version 2. - AuthorizedKeysFile may be used to specify an alternative file. + It is posible for protocol version 2 to contain X.509 certificates or + certificates ``Distinguished Name''. AuthorizedKeysFile may be used to + specify an alternative file. Each line of the file contains one key (empty lines and lines starting with a `#' are ignored as comments). Each RSA public key consists of the @@ -239,10 +245,19 @@ ulus and comment fields give the RSA key for protocol version 1; the com- ment field is not used for anything (but may be convenient for the user to identify the key). For protocol version 2 the keytype is ``ssh-dss'' - or ``ssh-rsa''. + or ``ssh-rsa''. In addition for protocol version 2 user can use X.509 + certificates. In that case keytype is ``x509v3-sign-rsa'' or + ``x509v3-sign-dss''. Instead of ``base64 encoded key'' line must contain + base64 encoded certicate (old style) or a keyword (new style), optional + followed by symbol `=' (equal) or `:' (colon), zero or more spaces and + certificate ``Distinguished Name'' (Subject). Keyword is case insensitive + and can be one of `Subject' , `Distinguished Name' , `Distinguished-Name' + , `Distinguished_Name' , `DistinguishedName' or `DN'. Separator of Sub- + ject items can be `/' (slash), `,' (comma) or mixed and order is not + important. - Note that lines in this file are usually several hundred bytes long (be- - cause of the size of the public key encoding) up to a limit of 8 kilo- + Note that lines in this file are usually several hundred bytes long + (because of the size of the public key encoding) up to a limit of 8 kilo- bytes, which permits DSA keys up to 8 kilobits and RSA keys up to 16 kilobits. You don't want to type them in; instead, copy the identity.pub, id_dsa.pub or the id_rsa.pub file and edit it. @@ -264,25 +279,25 @@ key is not accepted. The purpose of this option is to optionally increase security: public key authentication by itself does not trust the network or name servers or anything (but the key); how- - ever, if somebody somehow steals the key, the key permits an in- - truder to log in from anywhere in the world. This additional op- - tion makes using a stolen key more difficult (name servers and/or - routers would have to be compromised in addition to just the - key). + ever, if somebody somehow steals the key, the key permits an + intruder to log in from anywhere in the world. This additional + option makes using a stolen key more difficult (name servers + and/or routers would have to be compromised in addition to just + the key). command="command" Specifies that the command is executed whenever this key is used for authentication. The command supplied by the user (if any) is ignored. The command is run on a pty if the client requests a pty; otherwise it is run without a tty. If an 8-bit clean chan- - nel is required, one must not request a pty or should specify no- - pty. A quote may be included in the command by quoting it with a - backslash. This option might be useful to restrict certain pub- - lic keys to perform just a specific operation. An example might - be a key that permits remote backups but nothing else. Note that - the client may specify TCP/IP and/or X11 forwarding unless they - are explicitly prohibited. Note that this option applies to - shell, command or subsystem execution. + nel is required, one must not request a pty or should specify + no-pty. A quote may be included in the command by quoting it + with a backslash. This option might be useful to restrict cer- + tain public keys to perform just a specific operation. An exam- + ple might be a key that permits remote backups but nothing else. + Note that the client may specify TCP/IP and/or X11 forwarding + unless they are explicitly prohibited. Note that this option + applies to shell, command or subsystem execution. environment="NAME=value" Specifies that the string is to be added to the environment when @@ -294,8 +309,8 @@ no-port-forwarding Forbids TCP/IP forwarding when this key is used for authentica- - tion. Any port forward requests by the client will return an er- - ror. This might be used, e.g., in connection with the command + tion. Any port forward requests by the client will return an + error. This might be used, e.g., in connection with the command option. no-X11-forwarding @@ -313,25 +328,28 @@ nect to the specified host and port. IPv6 addresses can be spec- ified with an alternative syntax: host/port. Multiple permitopen options may be applied separated by commas. No pattern matching - is performed on the specified hostnames, they must be literal do- - mains or addresses. + is performed on the specified hostnames, they must be literal + domains or addresses. Examples 1024 33 12121...312314325 ylo@foo.bar from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23...2334 ylo@niksula - command="dump /home",no-pty,no-port-forwarding 1024 33 23...2323 back- - up.hut.fi + command="dump /home",no-pty,no-port-forwarding 1024 33 23...2323 + backup.hut.fi permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23...2323 + x509v3-sign-dss subject= /C=XX/ST=World/O=OpenSSH Test Team... + SSH_KNOWN_HOSTS FILE FORMAT The /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts files contain host - public keys for all known hosts. The global file should be prepared by - the administrator (optional), and the per-user file is maintained auto- - matically: whenever the user connects from an unknown host its key is - added to the per-user file. + public keys, certificates (old style) or certificates ``Distinguished + Name'' for all known hosts. The global file should be prepared by the + administrator (optional), and the per-user file is maintained automati- + cally: whenever the user connects from an unknown host its key is added + to the per-user file. Each line in these files contains the following fields: hostnames, bits, exponent, modulus, comment. The fields are separated by spaces. @@ -340,13 +358,13 @@ cards); each pattern in turn is matched against the canonical host name (when authenticating a client) or against the user-supplied name (when authenticating a server). A pattern may also be preceded by `!' to indi- - cate negation: if the host name matches a negated pattern, it is not ac- - cepted (by that line) even if it matched another pattern on the line. + cate negation: if the host name matches a negated pattern, it is not + accepted (by that line) even if it matched another pattern on the line. Alternately, hostnames may be stored in a hashed form which hides host names and addresses should the file's contents be disclosed. Hashed - hostnames start with a `|' character. Only one hashed hostname may ap- - pear on a single line and none of the above negation or wildcard opera- + hostnames start with a `|' character. Only one hashed hostname may + appear on a single line and none of the above negation or wildcard opera- tors may be applied. Bits, exponent, and modulus are taken directly from the RSA host key; @@ -372,6 +390,7 @@ closenet,...,130.233.208.41 1024 37 159...93 closenet.hut.fi cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234.....= + x509host x509v3-sign-rsa Subject:/C=XX..... # A hashed hostname |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa @@ -384,19 +403,23 @@ /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key - These three files contain the private parts of the host keys. - These files should only be owned by root, readable only by root, - and not accessible to others. Note that sshd does not start if - this file is group/world-accessible. + These three files contain the private parts of the host keys. It + is possible to contain private part followed by X.509 certificate + that match it for protocol version 2 keys. These files should + only be owned by root, readable only by root, and not accessible + to others. Note that sshd does not start if this file is + group/world-accessible. /etc/ssh/ssh_host_key.pub, /etc/ssh/ssh_host_dsa_key.pub, /etc/ssh/ssh_host_rsa_key.pub These three files contain the public parts of the host keys. These files should be world-readable but writable only by root. - Their contents should match the respective private parts. These - files are not really used for anything; they are provided for the - convenience of the user so their contents can be copied to known - hosts files. These files are created using ssh-keygen(1). + Their contents should match the respective private parts. Note + that when corresponding host key contain X.509 certificate these + files must contains that certificate. These files are not really + used for anything; they are provided for the convenience of the + user so their contents can be copied to known hosts files. These + files are created using ssh-keygen(1). /etc/moduli Contains Diffie-Hellman groups used for the "Diffie-Hellman Group @@ -416,33 +439,48 @@ able. ~/.ssh/authorized_keys - Lists the public keys (RSA or DSA) that can be used to log into - the user's account. This file must be readable by root (which - may on some machines imply it being world-readable if the user's - home directory resides on an NFS volume). It is recommended that - it not be accessible by others. The format of this file is de- - scribed above. Users will place the contents of their + Lists the public keys (RSA or DSA), certificates or certificates + ``Distinguished Names'' (recommendet) that can be used to log + into the user's account. This file must be readable by root + (which may on some machines imply it being world-readable if the + user's home directory resides on an NFS volume). It is recom- + mended that it not be accessible by others. The format of this + file is described above. Users will place the contents of their identity.pub, id_dsa.pub and/or id_rsa.pub files into this file, as described in ssh-keygen(1). /etc/ssh/ssh_known_hosts, ~/.ssh/known_hosts These files are consulted when using rhosts with RSA host authen- tication or protocol version 2 hostbased authentication to check - the public key of the host. The key must be listed in one of - these files to be accepted. The client uses the same files to - verify that it is connecting to the correct remote host. These - files should be writable only by root/the owner. + the public key or certificate of the host. The key must be + listed in one of these files to be accepted. The client uses the + same files to verify that it is connecting to the correct remote + host. These files should be writable only by root/the owner. /etc/ssh/ssh_known_hosts should be world-readable, and ~/.ssh/known_hosts can, but need not be, world-readable. + /etc/ssh/ca/ca-bundle.crt and /etc/ssh/ca/ca-bundle.crl + The first file contain multiple certificates and the second + ``Certificate Revocation List'' (CRLs) of certificate signers in + PEM format concatenated together. Used to verify and validate + client certificate. + + /etc/ssh/ca/crt and /etc/ssh/ca/crl + ``Hash dirs'' with certificates, the first directory or CLRs, the + second of certificate signers. Each certificate should be stored + in separate file with name [HASH].[NUMBER] or [HASH].r[NUMBER] + for the CRL, where [HASH] is certificate or CRL hash value and + [NUMBER] is an integer starting from zero. Used to verify and + validate client certificate. + /etc/motd See motd(5). ~/.hushlogin This file is used to suppress printing the last login time and - /etc/motd, if PrintLastLog and PrintMotd, respectively, are en- - abled. It does not suppress printing of the banner specified by - Banner. + /etc/motd, if PrintLastLog and PrintMotd, respectively, are + enabled. It does not suppress printing of the banner specified + by Banner. /etc/nologin If this file exists, sshd refuses to let anyone except root log @@ -451,8 +489,8 @@ world-readable. /etc/hosts.allow, /etc/hosts.deny - Access controls that should be enforced by tcp-wrappers are de- - fined here. Further details are described in hosts_access(5). + Access controls that should be enforced by tcp-wrappers are + defined here. Further details are described in hosts_access(5). ~/.rhosts This file is used during RhostsRSAAuthentication and @@ -483,18 +521,19 @@ ``+@group'' can be used to specify netgroups. Negated entries start with `-'. - If the client host/user is successfully matched in this file, lo- - gin is automatically permitted provided the client and server us- - er names are the same. Additionally, successful client host key - authentication is required. This file must be writable only by - root; it is recommended that it be world-readable. + If the client host/user is successfully matched in this file, + login is automatically permitted provided the client and server + user names are the same. Additionally, successful client host + key authentication is required. This file must be writable only + by root; it is recommended that it be world-readable. Warning: It is almost never a good idea to use user names in hosts.equiv. Beware that it really means that the named user(s) can log in as anybody, which includes bin, daemon, adm, and other - accounts that own critical binaries and directories. Using a us- - er name practically grants the user root access. The only valid - use for user names that I can think of is in negative entries. + accounts that own critical binaries and directories. Using a + user name practically grants the user root access. The only + valid use for user names that I can think of is in negative + entries. Note that this warning also applies to rsh/rlogin. @@ -512,18 +551,18 @@ is controlled via the PermitUserEnvironment option. ~/.ssh/rc - If this file exists, it is run with /bin/sh after reading the en- - vironment files but before starting the user's shell or command. - It must not produce any output on stdout; stderr must be used in- - stead. If X11 forwarding is in use, it will receive the "proto - cookie" pair in its standard input (and DISPLAY in its environ- - ment). The script must call xauth(1) because sshd will not run - xauth automatically to add X11 cookies. + If this file exists, it is run with /bin/sh after reading the + environment files but before starting the user's shell or com- + mand. It must not produce any output on stdout; stderr must be + used instead. If X11 forwarding is in use, it will receive the + "proto cookie" pair in its standard input (and DISPLAY in its + environment). The script must call xauth(1) because sshd will + not run xauth automatically to add X11 cookies. The primary purpose of this file is to run any initialization - routines which may be needed before the user's home directory be- - comes accessible; AFS is a particular example of such an environ- - ment. + routines which may be needed before the user's home directory + becomes accessible; AFS is a particular example of such an envi- + ronment. This file will probably contain some initialization code followed by something similar to: @@ -546,9 +585,9 @@ readable by anyone else. /etc/ssh/sshrc - Like ~/.ssh/rc. This can be used to specify machine-specific lo- - gin-time initializations globally. This file should be writable - only by root, and should be world-readable. + Like ~/.ssh/rc. This can be used to specify machine-specific + login-time initializations globally. This file should be + writable only by root, and should be world-readable. SEE ALSO scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), @@ -566,9 +605,10 @@ AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo - de Raadt and Dug Song removed many bugs, re-added newer features and - created OpenSSH. Markus Friedl contributed the support for SSH protocol + 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. Niels Provos and Markus Friedl contributed support - for privilege separation. + for privilege separation. Roumen Petrov contributed support for X.509 + certificates. -OpenBSD 3.8 September 25, 1999 9 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/sshd.8 openssh-4.2p1+x509-5.5/sshd.8 --- openssh-4.2p1/sshd.8 2005-06-16 06:19:07.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd.8 2006-01-15 09:06:00.000000000 +0200 @@ -13,6 +13,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -34,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.208 2005/06/08 03:50:00 djm Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -145,6 +146,8 @@ .Ss SSH protocol version 2 Version 2 works similarly: Each host has a host-specific key (RSA or DSA) used to identify the host. +It is possible host key to contain private key +followed by X.509 certificate that match it. However, when the daemon starts, it does not generate a server key. Forward security is provided through a Diffie-Hellman key agreement. This key agreement results in a shared session key. @@ -252,6 +255,8 @@ for protocol version 2. It is possible to have multiple host key files for the different protocol versions and host key algorithms. +It is possible host key for protocol version 2 to contain private key +followed by X.509 certificate that match it. .It Fl i Specifies that .Nm @@ -395,6 +400,9 @@ permitted for RSA authentication in protocol version 1 and for public key authentication (PubkeyAuthentication) in protocol version 2. +It is posible for protocol version 2 to contain X.509 certificates +or certificates +.Dq "Distinguished Name" . .Cm AuthorizedKeysFile may be used to specify an alternative file. .Pp @@ -418,6 +426,37 @@ .Dq ssh-dss or .Dq ssh-rsa . +In addition for protocol version 2 user can use X.509 certificates. +In that case keytype is +.Dq x509v3-sign-rsa +or +.Dq x509v3-sign-dss . +Instead of +.Dq "base64 encoded key" +line must contain base64 encoded certicate (old style) or +a keyword (new style), optional followed by symbol +.Sq = +(equal) or +.Sq \&: +(colon), zero or more spaces and certificate +.Dq "Distinguished Name" +(Subject). Keyword is case insensitive and can be one of +.Sq Subject +, +.Sq "Distinguished Name" +, +.Sq Distinguished-Name +, +.Sq Distinguished_Name +, +.Sq DistinguishedName +or +.Sq DN . +Separator of Subject items can be +.Sq / +(slash), +.Sq \&, +(comma) or mixed and order is not important. .Pp Note that lines in this file are usually several hundred bytes long (because of the size of the public key encoding) up to a limit of @@ -524,12 +563,16 @@ command="dump /home",no-pty,no-port-forwarding 1024 33 23...2323 backup.hut.fi .Pp permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23...2323 +.Pp +x509v3-sign-dss subject= /C=XX/ST=World/O=OpenSSH Test Team... .Sh SSH_KNOWN_HOSTS FILE FORMAT The .Pa /etc/ssh/ssh_known_hosts and .Pa ~/.ssh/known_hosts -files contain host public keys for all known hosts. +files contain host public keys, certificates (old style) or certificates +.Dq "Distinguished Name" +for all known hosts. The global file should be prepared by the administrator (optional), and the per-user file is maintained automatically: whenever the user connects from an unknown host @@ -591,6 +634,7 @@ .Bd -literal closenet,...,130.233.208.41 1024 37 159...93 closenet.hut.fi cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234.....= +x509host x509v3-sign-rsa Subject:/C=XX..... .Ed .Bd -literal # A hashed hostname @@ -606,6 +650,9 @@ .Xr sshd_config 5 . .It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key These three files contain the private parts of the host keys. +It is possible to contain private part +followed by X.509 certificate that match it +for protocol version 2 keys. These files should only be owned by root, readable only by root, and not accessible to others. Note that @@ -616,6 +663,8 @@ These files should be world-readable but writable only by root. Their contents should match the respective private parts. +Note that when corresponding host key contain X.509 certificate +these files must contains that certificate. These files are not really used for anything; they are provided for the convenience of the user so their contents can be copied to known hosts files. @@ -640,7 +689,10 @@ started last). The content of this file is not sensitive; it can be world-readable. .It Pa ~/.ssh/authorized_keys -Lists the public keys (RSA or DSA) that can be used to log into the user's account. +Lists the public keys (RSA or DSA), certificates or certificates +.Dq "Distinguished Names" +(recommendet) +that can be used to log into the user's account. This file must be readable by root (which may on some machines imply it being world-readable if the user's home directory resides on an NFS volume). @@ -656,7 +708,7 @@ .It Pa "/etc/ssh/ssh_known_hosts", "~/.ssh/known_hosts" These files are consulted when using rhosts with RSA host authentication or protocol version 2 hostbased authentication -to check the public key of the host. +to check the public key or certificate of the host. The key must be listed in one of these files to be accepted. The client uses the same files to verify that it is connecting to the correct remote host. @@ -665,6 +717,20 @@ should be world-readable, and .Pa ~/.ssh/known_hosts can, but need not be, world-readable. +.It Pa "/etc/ssh/ca/ca-bundle.crt" and "/etc/ssh/ca/ca-bundle.crl" +The first file contain multiple certificates and the second +.Dq "Certificate Revocation List" +(CRLs) of certificate signers in PEM format concatenated together. +Used to verify and validate client certificate. +.It Pa "/etc/ssh/ca/crt" and Pa "/etc/ssh/ca/crl" +.Dq "Hash dirs" +with certificates, the first directory or CLRs, the second of +certificate signers. +Each certificate should be stored in separate file with name +[HASH].[NUMBER] or [HASH].r[NUMBER] for the CRL, where [HASH] is +certificate or CRL hash value and [NUMBER] is an integer starting +from zero. +Used to verify and validate client certificate. .It Pa /etc/motd See .Xr motd 5 . @@ -864,3 +930,4 @@ protocol versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support for privilege separation. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/sshd.c openssh-4.2p1+x509-5.5/sshd.c --- openssh-4.2p1/sshd.c 2005-07-26 14:54:56.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd.c 2006-01-15 09:06:01.000000000 +0200 @@ -20,6 +20,9 @@ * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. * + * X.509 certificates support: + * 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 * are met: @@ -42,7 +45,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.312 2005/07/25 11:59:40 markus Exp $"); +RCSID("$OpenBSD$"); #include #include @@ -85,6 +88,7 @@ #include "monitor.h" #include "monitor_wrap.h" #include "monitor_fdpass.h" +#include "ssh-xkalg.h" #ifdef LIBWRAP #include @@ -105,6 +109,9 @@ extern char *__progname; +/* ssh-x509.c needs this */ +extern int (*pssh_x509cert_check)(X509 *cert); + /* Server configuration options. */ ServerOptions options; @@ -700,6 +707,10 @@ p = key_ssh_name(key); buffer_append(&b, p, strlen(p)); break; + case KEY_X509_RSA: + case KEY_X509_DSA: + ssh_list_xkalg(key->type, &b); + break; } } buffer_append(&b, "\0", 1); @@ -896,6 +907,7 @@ #endif __progname = ssh_get_progname(av[0]); init_rng(); + pssh_x509cert_check = ssh_x509cert_check; /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ saved_argc = ac; @@ -1107,6 +1119,8 @@ break; case KEY_RSA: case KEY_DSA: + case KEY_X509_RSA: + case KEY_X509_DSA: sensitive_data.have_ssh2_key = 1; break; } diff -ruN openssh-4.2p1/sshd_config openssh-4.2p1+x509-5.5/sshd_config --- openssh-4.2p1/sshd_config 2005-07-26 14:54:57.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd_config 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.72 2005/07/25 11:59:40 markus Exp $ +# $OpenBSD$ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -22,6 +22,69 @@ #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key +# "key type names" for X.509 certificates with RSA key +# Note first defined is used in signature operations! +#X509KeyAlgorithm x509v3-sign-rsa,rsa-md5 +#X509KeyAlgorithm x509v3-sign-rsa,rsa-sha1 + +# "key type names" for X.509 certificates with DSA key +# Note first defined is used in signature operations! +#X509KeyAlgorithm x509v3-sign-dss,dss-asn1 +#X509KeyAlgorithm x509v3-sign-dss,dss-raw + +# The intended use for the X509 client certificate. Without this option +# no chain verification will be done. Currently accepted uses are case +# insensitive: +# - "sslclient", "SSL client", "SSL_client" or "client" +# - "any", "Any Purpose", "Any_Purpose" or "AnyPurpose" +# - "skip" or ""(empty): don`t check purpose. +#AllowedCertPurpose sslclient + +# Specifies whether self-issued(self-signed) X.509 certificate can be +# allowed only by entry in AutorizedKeysFile that contain matching +# public key or certificate blob. +#KeyAllowSelfIssued no + +# Specifies whether CRL must present in store for all certificates in +# certificate chain with atribute "cRLDistributionPoints" +#MandatoryCRL no + +# A file with multiple certificates of certificate signers +# in PEM format concatenated together. +#CACertificateFile /etc/ssh/ca/ca-bundle.crt + +# A directory with certificates of certificate signers. +# The certificates should have name of the form: [HASH].[NUMBER] +# or have symbolic links to them of this form. +#CACertificatePath /etc/ssh/ca/crt + +# A file with multiple CRL of certificate signers +# in PEM format concatenated together. +#CARevocationFile /etc/ssh/ca/ca-bundle.crl + +# A directory with CRL of certificate signers. +# The CRL should have name of the form: [HASH].r[NUMBER] +# or have symbolic links to them of this form. +#CARevocationPath /etc/ssh/ca/crl + +# LDAP protocol version. +# Example: +# CAldapVersion 2 + +# Note because of OpenSSH options parser limitation +# use %3D instead of = ! +# Example: +# CAldapURL ldap://localhost:389/dc%3Dexample,dc%3Dcom + +# SSH can use "Online Certificate Status Protocol"(OCSP) +# to validate certificate. Set VAType to +# - none : do not use OCSP to validate certificates; +# - ocspcert: validate only certificates that specify `OCSP +# Service Locator' URL; +# - ocspspec: use specified in the configuration 'OCSP Responder' +# to validate all certificates. +#VAType none + # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h #ServerKeyBits 768 diff -ruN openssh-4.2p1/sshd_config.0 openssh-4.2p1+x509-5.5/sshd_config.0 --- openssh-4.2p1/sshd_config.0 2005-09-01 12:15:26.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd_config.0 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -SSHD_CONFIG(5) OpenBSD Programmer's Manual SSHD_CONFIG(5) +SSHD_CONFIG(5) System File Formats Manual SSHD_CONFIG(5) NAME sshd_config - OpenSSH SSH daemon configuration file @@ -29,10 +29,19 @@ any environment variables. AddressFamily - Specifies which address family should be used by sshd. Valid ar- - guments are ``any'', ``inet'' (use IPv4 only) or ``inet6'' (use + Specifies which address family should be used by sshd. Valid + arguments are ``any'', ``inet'' (use IPv4 only) or ``inet6'' (use IPv6 only). The default is ``any''. + AllowedCertPurpose + 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' ; + o `any' , `Any Purpose' , `Any_Purpose' or `AnyPurpose' ; + o `skip' or `' (empty): do not check purpose. + The default is ``sslclient''. + AllowGroups This keyword can be followed by a list of group name patterns, separated by spaces. If specified, login is allowed only for @@ -43,30 +52,30 @@ AllowTcpForwarding Specifies whether TCP forwarding is permitted. The default is - ``yes''. Note that disabling TCP forwarding does not improve se- - curity unless users are also denied shell access, as they can al- - ways install their own forwarders. + ``yes''. Note that disabling TCP forwarding does not improve + security unless users are also denied shell access, as they can + always install their own forwarders. AllowUsers This keyword can be followed by a list of user name patterns, - separated by spaces. If specified, login is allowed only for us- - er names that match one of the patterns. `*' and `?' can be used - as wildcards in the patterns. Only user names are valid; a nu- - merical user ID is not recognized. By default, login is allowed - for all users. If the pattern takes the form USER@HOST then USER - and HOST are separately checked, restricting logins to particular - users from particular hosts. + separated by spaces. If specified, login is allowed only for + user names that match one of the patterns. `*' and `?' can be + used as wildcards in the patterns. Only user names are valid; a + numerical user ID is not recognized. By default, login is + allowed for all users. If the pattern takes the form USER@HOST + then USER and HOST are separately checked, restricting logins to + particular users from particular hosts. AuthorizedKeysFile Specifies the file that contains the public keys that can be used for user authentication. AuthorizedKeysFile may contain tokens of the form %T which are substituted during connection set-up. The following tokens are defined: %% is replaced by a literal - '%', %h is replaced by the home directory of the user being au- - thenticated and %u is replaced by the username of that user. Af- - ter expansion, AuthorizedKeysFile is taken to be an absolute path - or one relative to the user's home directory. The default is - ``.ssh/authorized_keys''. + '%', %h is replaced by the home directory of the user being + authenticated and %u is replaced by the username of that user. + After expansion, AuthorizedKeysFile is taken to be an absolute + path or one relative to the user's home directory. The default + is ``.ssh/authorized_keys''. Banner In some jurisdictions, sending a warning message before authenti- cation may be relevant for getting legal protection. The con- @@ -74,6 +83,40 @@ authentication is allowed. This option is only available for protocol version 2. By default, no banner is displayed. + CACertificateFile + ``X509 store'' option: This file contain multiple certificates of + certificate signers in PEM format concatenated together. The + default is /etc/ssh/ca/ca-bundle.crt. + + CACertificatePath + ``X509 store'' option: ``Hash dir'' with certificates of certifi- + cate signers. Each certificate should be stored in separate file + with name [HASH].[NUMBER], where [HASH] is certificate hash value + and [NUMBER] is an integer starting from zero. The default is + /etc/ssh/ca/crt. + + CAldapVersion + ``X509 store'' option: Specifies LDAP protocol version. The + default is not specified and depend from LDAP library. + + CAldapURL + ``X509 store'' option: Specifies hostport and dn(distinguished + name) of LDAP URLs (Uniform Resource Locators) as detailed in RFC + 2255. The rest of URL is build internally. Because of OpenSSH + options parser limitation use `%3D' instead of `=' ! + + CARevocationFile + ``X509 store'' option: This file contain multiple ``Certificate + Revocation List'' (CRL) of certificate signers in PEM format con- + catenated together. The default is /etc/ssh/ca/ca-bundle.crl. + + CARevocationPath + ``X509 store'' option: ``Hash dir'' with ``Certificate Revocation + List'' (CRL) of certificate signers. Each CRL should be stored in + separate file with name [HASH].r[NUMBER], where [HASH] is CRL + hash value and [NUMBER] is an integer starting from zero. The + default is /etc/ssh/ca/crl. + ChallengeResponseAuthentication Specifies whether challenge response authentication is allowed. All authentication styles from login.conf(5) are supported. The @@ -94,8 +137,8 @@ ClientAliveCountMax Sets the number of client alive messages (see above) which may be sent without sshd receiving any messages back from the client. - If this threshold is reached while client alive messages are be- - ing sent, sshd will disconnect the client, terminating the ses- + If this threshold is reached while client alive messages are + being sent, sshd will disconnect the client, terminating the ses- sion. It is important to note that the use of client alive mes- sages is very different from TCPKeepAlive (below). The client alive messages are sent through the encrypted channel and there- @@ -125,8 +168,8 @@ separated by spaces. Login is disallowed for users whose primary group or supplementary group list matches one of the patterns. `*' and `?' can be used as wildcards in the patterns. Only group - names are valid; a numerical group ID is not recognized. By de- - fault, login is allowed for all groups. + names are valid; a numerical group ID is not recognized. By + default, login is allowed for all groups. DenyUsers This keyword can be followed by a list of user name patterns, @@ -146,8 +189,8 @@ used to specify that sshd should allow remote port forwardings to bind to non-loopback addresses, thus allowing other hosts to con- nect. The argument may be ``no'' to force remote port forward- - ings to be available to the local host only, ``yes'' to force re- - mote port forwardings to bind to the wildcard address, or + ings to be available to the local host only, ``yes'' to force + remote port forwardings to bind to the wildcard address, or ``clientspecified'' to allow the client to select the address to which the forwarding is bound. The default is ``no''. @@ -161,9 +204,17 @@ cache on logout. The default is ``yes''. Note that this option applies to protocol version 2 only. + HostbasedAlgorithms + Specifies the protocol version 2 algorithms used in ``hostbased'' + authentication that the server accept. The default is all sup- + ported by server. Note algorithms that use X.509 certificates + depend from X509KeyAlgorithm and one of names set in + X509KeyAlgorithm for a certain key-type is enough to enable all + form that key-type. + HostbasedAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication to- - gether with successful public key client host authentication is + Specifies whether rhosts or /etc/hosts.equiv authentication + together with successful public key client host authentication is allowed (hostbased authentication). This option is similar to RhostsRSAAuthentication and applies to protocol version 2 only. The default is ``no''. @@ -175,14 +226,16 @@ tocol version 2. Note that sshd will refuse to use a file if it is group/world-accessible. It is possible to have multiple host key files. ``rsa1'' keys are used for version 1 and ``dsa'' or - ``rsa'' are used for version 2 of the SSH protocol. + ``rsa'' are used for version 2 of the SSH protocol. For version + 2 is possible file to contain private key followed by X.509 cer- + tificate that match the key. IgnoreRhosts Specifies that .rhosts and .shosts files will not be used in RhostsRSAAuthentication or HostbasedAuthentication. - /etc/hosts.equiv and /etc/shosts.equiv are still used. The de- - fault is ``yes''. + /etc/hosts.equiv and /etc/shosts.equiv are still used. The + default is ``yes''. IgnoreUserKnownHosts Specifies whether sshd should ignore the user's @@ -210,6 +263,21 @@ Specifies whether to automatically destroy the user's ticket cache file on logout. Default is ``yes''. + KeyAllowSelfIssued + Specifies whether only public key or certificate blob listed in + AutorizedKeysFile can allow self-issued(self-signed) X.509 cer- + tificate to be used for user authentication. The default is + ``no''. + + A certificate (including self-issued) is accepted for user + authentication if its public key blob, certificate blob or dis- + tinguished name is listed in AutorizedKeysFile, if is valid and + if is verified by certificates from ``X509 store''. See + verify(1). In addition if option is set to ``yes'' self-issued + certificate is accepted when its public key match public key + extracted from entry in AutorizedKeysFile. In this case validity + of certificate is not checked. + KeyRegenerationInterval In protocol version 1, the ephemeral server key is automatically regenerated after this many seconds (if it has been used). The @@ -247,9 +315,14 @@ MACs Specifies the available MAC (message authentication code) algo- rithms. The MAC algorithm is used in protocol version 2 for data - integrity protection. Multiple algorithms must be comma-separat- - ed. The default is ``hmac-md5,hmac-sha1,hmac-ripemd160,hmac- - sha1-96,hmac-md5-96''. + integrity protection. Multiple algorithms must be comma-sepa- + rated. The default is + ``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96''. + + MandatoryCRL + ``X509 store'' option: Specifies whether CRL must present in + store for all certificates in ``certificate chain'' with atribute + ``X509v3 CRL Distribution Points''. The default is ``no''. MaxAuthTries Specifies the maximum number of authentication attempts permitted @@ -259,8 +332,8 @@ MaxStartups Specifies the maximum number of concurrent unauthenticated con- nections to the sshd daemon. Additional connections will be - dropped until authentication succeeds or the LoginGraceTime ex- - pires for a connection. The default is 10. + dropped until authentication succeeds or the LoginGraceTime + expires for a connection. The default is 10. Alternatively, random early drop can be enabled by specifying the three colon separated values ``start:rate:full'' (e.g., @@ -271,8 +344,8 @@ unauthenticated connections reaches ``full'' (60). PasswordAuthentication - Specifies whether password authentication is allowed. The de- - fault is ``yes''. + Specifies whether password authentication is allowed. The + default is ``yes''. PermitEmptyPasswords When password authentication is allowed, it specifies whether the @@ -298,9 +371,9 @@ PermitUserEnvironment Specifies whether ~/.ssh/environment and environment= options in ~/.ssh/authorized_keys are processed by sshd. The default is - ``no''. Enabling environment processing may enable users to by- - pass access restrictions in some configurations using mechanisms - such as LD_PRELOAD. + ``no''. Enabling environment processing may enable users to + bypass access restrictions in some configurations using mecha- + nisms such as LD_PRELOAD. PidFile Specifies the file that contains the process ID of the sshd dae- @@ -324,25 +397,33 @@ Specifies the protocol versions sshd supports. The possible val- ues are ``1'' and ``2''. Multiple versions must be comma-sepa- rated. The default is ``2,1''. Note that the order of the pro- - tocol list does not indicate preference, because the client se- - lects among multiple protocol versions offered by the server. + tocol list does not indicate preference, because the client + selects among multiple protocol versions offered by the server. Specifying ``2,1'' is identical to ``1,2''. + PubkeyAlgorithms + Specifies the protocol version 2 algorithms used in ``publickey'' + authentication that the server accept. The default is all sup- + ported by server. Note algorithms that use X.509 certificates + depend from X509KeyAlgorithm and one of names set in + X509KeyAlgorithm for a certain key-type is enough to enable all + form that key-type. + PubkeyAuthentication - Specifies whether public key authentication is allowed. The de- - fault is ``yes''. Note that this option applies to protocol ver- - sion 2 only. + Specifies whether public key authentication is allowed. The + default is ``yes''. Note that this option applies to protocol + version 2 only. RhostsRSAAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication to- - gether with successful RSA host authentication is allowed. The - default is ``no''. This option applies to protocol version 1 on- - ly. + Specifies whether rhosts or /etc/hosts.equiv authentication + together with successful RSA host authentication is allowed. The + default is ``no''. This option applies to protocol version 1 + only. RSAAuthentication - Specifies whether pure RSA authentication is allowed. The de- - fault is ``yes''. This option applies to protocol version 1 on- - ly. + Specifies whether pure RSA authentication is allowed. The + default is ``yes''. This option applies to protocol version 1 + only. ServerKeyBits Defines the number of bits in the ephemeral protocol version 1 @@ -357,17 +438,17 @@ Subsystem Configures an external subsystem (e.g., file transfer daemon). - Arguments should be a subsystem name and a command to execute up- - on subsystem request. The command sftp-server(8) implements the - ``sftp'' file transfer subsystem. By default no subsystems are - defined. Note that this option applies to protocol version 2 on- - ly. + Arguments should be a subsystem name and a command to execute + upon subsystem request. The command sftp-server(8) implements + the ``sftp'' file transfer subsystem. By default no subsystems + are defined. Note that this option applies to protocol version 2 + only. SyslogFacility Gives the facility code that is used when logging messages from - sshd. The possible values are: DAEMON, USER, AUTH, LOCAL0, LO- - CAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The de- - fault is AUTH. + sshd. The possible values are: DAEMON, USER, AUTH, LOCAL0, + LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The + default is AUTH. TCPKeepAlive Specifies whether the system should send TCP keepalive messages @@ -376,8 +457,8 @@ this means that connections will die if the route is down tem- porarily, and some people find it annoying. On the other hand, if TCP keepalives are not sent, sessions may hang indefinitely on - the server, leaving ``ghost'' users and consuming server re- - sources. + the server, leaving ``ghost'' users and consuming server + resources. The default is ``yes'' (to send TCP keepalive messages), and the server will notice if the network goes down or the client host @@ -393,8 +474,8 @@ UseLogin Specifies whether login(1) is used for interactive login ses- sions. The default is ``no''. Note that login(1) is never used - for remote command execution. Note also, that if this is en- - abled, X11Forwarding will be disabled because login(1) does not + for remote command execution. Note also, that if this is + enabled, X11Forwarding will be disabled because login(1) does not know how to handle xauth(1) cookies. If UsePrivilegeSeparation is specified, it will be disabled after authentication. @@ -411,14 +492,36 @@ non-root user. The default is ``no''. UsePrivilegeSeparation - Specifies whether sshd separates privileges by creating an un- - privileged child process to deal with incoming network traffic. + Specifies whether sshd separates privileges by creating an + unprivileged child process to deal with incoming network traffic. After successful authentication, another process will be created that has the privilege of the authenticated user. The goal of privilege separation is to prevent privilege escalation by con- taining any corruption within the unprivileged processes. The default is ``yes''. + VACertificateFile + File with X.509 certificates in PEM format concatenated together. + In use when VAType is set to ``ocspspec''. The default value is + `' (empty). Certificates from that file explicitly trust `OCSP + Responder' public key. They are used as trusted certificates in + addition to certificates from CACertificateFile and + CACertificatePath to verify responder certificate. + + VAType Specifies whether `Online Certificate Status Protocol' (OCSP) is + used to validate X.509 certificates. Accepted values are case + insensitive: + o `none' : do not use OCSP to validate certificates; + o `ocspcert' : validate only certificates that specify `OCSP + Service Locator' URL; + o `ocspspec' : use specified in the configuration `OCSP + Responder' to validate all certificates. + The default is ``none''. + + VAOCSPResponderURL + `Access Location' / `OCSP Service Locator' URL of the OCSP + provider. In use when VAType is set to ``ocspspec''. + X11DisplayOffset Specifies the first display number available for sshd's X11 for- warding. This prevents sshd from interfering with real X11 @@ -431,11 +534,11 @@ When X11 forwarding is enabled, there may be additional exposure to the server and to client displays if the sshd proxy display is configured to listen on the wildcard address (see X11UseLocalhost - below), however this is not the default. Additionally, the au- - thentication spoofing and authentication data verification and - substitution occur on the client side. The security risk of us- - ing X11 forwarding is that the client's X11 display server may be - exposed to attack when the ssh client requests forwarding (see + below), however this is not the default. Additionally, the + authentication spoofing and authentication data verification and + substitution occur on the client side. The security risk of + using X11 forwarding is that the client's X11 display server may + be exposed to attack when the ssh client requests forwarding (see the warnings for ForwardX11 in ssh_config(5)). A system adminis- trator may have a stance in which they want to protect clients that may expose themselves to attack by unwittingly requesting @@ -455,8 +558,26 @@ proxy display. However, some older X11 clients may not function with this configuration. X11UseLocalhost may be set to ``no'' to specify that the forwarding server should be bound to the wild- - card address. The argument must be ``yes'' or ``no''. The de- - fault is ``yes''. + card address. The argument must be ``yes'' or ``no''. The + default is ``yes''. + + X509KeyAlgorithm + Specifies how X.509 certificates and signatures are used for pro- + tocol version 2. It is possible to have multiple algorithms in + form specified in X509 Key Algorithms Format. sshd use the first + listed for ``rsa'' or ``dsa'' key in signing and accept all + listed. + + The default for certificates with RSA key is: + X509KeyAlgorithm x509v3-sign-rsa,rsa-md5 + X509KeyAlgorithm x509v3-sign-rsa,rsa-sha1 + + The default for certificates with DSA key is: + X509KeyAlgorithm x509v3-sign-dss,dss-asn1 + X509KeyAlgorithm x509v3-sign-dss,dss-raw + + X509rsaSigType + Deprecated option replaced by X509KeyAlgorithm. XAuthLocation Specifies the full pathname of the xauth(1) program. The default @@ -484,6 +605,19 @@ 10m 10 minutes 1h30m 1 hour 30 minutes (90 minutes) + X509 Key Algorithms Format + sshd command-line arguments and configuration file options that specify + `X509 Key Algorithms' expressed using a sequence of the form: + key-type-name,digest-name[,signature-identifier], where key-type-name is + key type name, digest-name is + rsa-md5 : RSA key and signature using the MD5 hash; + rsa-sha1 : RSA key and signature using the SHA-1 hash; + dss-asn1 : DSA key and signature as specified in ``RFC3279'' ; + dss-raw : DSA key and signature in ``ssh-dss'' format specified + in ``SecSH transport'' draft . + and optional signature-identifier. When signature-identifier is omited + key-type-name is used as identifier. + FILES /etc/ssh/sshd_config Contains configuration data for sshd. This file should be @@ -499,6 +633,7 @@ 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. Niels Provos and Markus Friedl contributed support - for privilege separation. + for privilege separation. Roumen Petrov contributed support for X.509 + certificates. -OpenBSD 3.8 September 25, 1999 8 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/sshd_config.5 openssh-4.2p1+x509-5.5/sshd_config.5 --- openssh-4.2p1/sshd_config.5 2005-07-26 14:54:57.000000000 +0300 +++ openssh-4.2p1+x509-5.5/sshd_config.5 2006-04-26 09:06:00.000000000 +0300 @@ -13,6 +13,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002-2006 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -34,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.44 2005/07/25 11:59:40 markus Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSHD_CONFIG 5 .Os @@ -94,6 +95,38 @@ (use IPv6 only). The default is .Dq any . +.It Cm AllowedCertPurpose +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 +.It +.Sq sslclient +, +.Sq SSL client +, +.Sq SSL_client +or +.Sq client +; +.It +.Sq any +, +.Sq Any Purpose +, +.Sq Any_Purpose +or +.Sq AnyPurpose +; +.It +.Sq skip +or +.Sq +.. +(empty): do not check purpose. +.El +The default is +.Dq sslclient . .It Cm AllowGroups This keyword can be followed by a list of group name patterns, separated by spaces. @@ -150,6 +183,54 @@ authentication is allowed. This option is only available for protocol version 2. By default, no banner is displayed. +.It Cm CACertificateFile +.Dq X509 store +option: +This file contain multiple certificates of certificate signers in +PEM format concatenated together. The default is +.Pa /etc/ssh/ca/ca-bundle.crt . +.It Cm CACertificatePath +.Dq X509 store +option: +.Dq "Hash dir" +with certificates of certificate signers. Each certificate should be +stored in separate file with name [HASH].[NUMBER], where [HASH] is +certificate hash value and [NUMBER] is an integer starting from zero. +The default is +.Pa /etc/ssh/ca/crt . +.It Cm CAldapVersion +.Dq X509 store +option: +Specifies LDAP protocol version. +The default is not specified and depend from LDAP library. +.It Cm CAldapURL +.Dq X509 store +option: +Specifies hostport and dn(distinguished name) of LDAP URLs (Uniform Resource Locators) as detailed in RFC 2255. +The rest of URL is build internally. +Because of OpenSSH options parser limitation use +.Sq %3D +instead of +.Sq = +! +.It Cm CARevocationFile +.Dq X509 store +option: +This file contain multiple +.Dq "Certificate Revocation List" +(CRL) of certificate signers in PEM format concatenated together. +The default is +.Pa /etc/ssh/ca/ca-bundle.crl . +.It Cm CARevocationPath +.Dq X509 store +option: +.Dq "Hash dir" +with +.Dq "Certificate Revocation List" +(CRL) of certificate signers. Each CRL should be stored in separate +file with name [HASH].r[NUMBER], where [HASH] is CRL hash value and +[NUMBER] is an integer starting from zero. The default is +.Pa /etc/ssh/ca/crl . .It Cm ChallengeResponseAuthentication Specifies whether challenge response authentication is allowed. All authentication styles from @@ -283,6 +364,16 @@ The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm HostbasedAlgorithms +Specifies the protocol version 2 algorithms used in +.Dq hostbased +authentication that the server accept. +The default is all supported by server. +Note algorithms that use X.509 certificates depend from +.Cm X509KeyAlgorithm +and one of names set in +.Cm X509KeyAlgorithm +for a certain key-type is enough to enable all form that key-type. .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed @@ -312,6 +403,8 @@ or .Dq rsa are used for version 2 of the SSH protocol. +For version 2 is possible file to contain private key +followed by X.509 certificate that match the key. .It Cm IgnoreRhosts Specifies that .Pa .rhosts @@ -364,6 +457,28 @@ file on logout. Default is .Dq yes . +.It Cm KeyAllowSelfIssued +Specifies whether only public key or certificate blob listed in +.Cm AutorizedKeysFile +can allow self-issued(self-signed) X.509 certificate +to be used for user authentication. +The default is +.Dq no . +.Pp +A certificate (including self-issued) is accepted +for user authentication if its public key blob, +certificate blob or distinguished name is listed in +.Cm AutorizedKeysFile , +if is valid and if is verified by certificates from +.Dq X509 store . +See +.Xr verify 1 . +In addition if option is set to +.Dq yes +self-issued certificate is accepted when its public key +match public key extracted from entry in +.Cm AutorizedKeysFile . +In this case validity of certificate is not checked. .It Cm KeyRegenerationInterval In protocol version 1, the ephemeral server key is automatically regenerated after this many seconds (if it has been used). @@ -433,6 +548,15 @@ Multiple algorithms must be comma-separated. The default is .Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 . +.It Cm MandatoryCRL +.Dq X509 store +option: +Specifies whether CRL must present in store for all certificates in +.Dq certificate chain +with atribute +.Dq X509v3 CRL Distribution Points . +The default is +.Dq no . .It Cm MaxAuthTries Specifies the maximum number of authentication attempts permitted per connection. @@ -566,6 +690,16 @@ .Dq 2,1 is identical to .Dq 1,2 . +.It Cm PubkeyAlgorithms +Specifies the protocol version 2 algorithms used in +.Dq publickey +authentication that the server accept. +The default is all supported by server. +Note algorithms that use X.509 certificates depend from +.Cm X509KeyAlgorithm +and one of names set in +.Cm X509KeyAlgorithm +for a certain key-type is enough to enable all form that key-type. .It Cm PubkeyAuthentication Specifies whether public key authentication is allowed. The default is @@ -691,6 +825,54 @@ escalation by containing any corruption within the unprivileged processes. The default is .Dq yes . +.It Cm VACertificateFile +File with X.509 certificates in PEM format concatenated together. +In use when +.Cm VAType +is set to +.Dq ocspspec . +The default value is +.Sq +.. +(empty). +Certificates from that file explicitly trust +.Sq "OCSP Responder" +public key. +They are used as trusted certificates in addition to certificates from +.Cm CACertificateFile +and +.Cm CACertificatePath +to verify responder certificate. +.It Cm VAType +Specifies whether +.Sq "Online Certificate Status Protocol" +(OCSP) is used to validate X.509 certificates. +Accepted values are case insensitive: +.Bl -bullet -compact +.It +.Sq none +: do not use OCSP to validate certificates; +.It +.Sq ocspcert +: validate only certificates that specify +.Sq "OCSP Service Locator" +URL; +.It +.Sq ocspspec +: use specified in the configuration +.Sq "OCSP Responder" +to validate all certificates. +.El +The default is +.Dq none . +.It Cm VAOCSPResponderURL +.Sq "Access Location" +/ +.Sq "OCSP Service Locator" +URL of the OCSP provider. In use when +.Cm VAType +is set to +.Dq ocspspec . .It Cm X11DisplayOffset Specifies the first display number available for .Nm sshd Ns 's @@ -759,6 +941,48 @@ .Dq no . The default is .Dq yes . +.It Cm X509KeyAlgorithm +Specifies how X.509 certificates and signatures are used for protocol version 2. +It is possible to have multiple algorithms +in form specified in +.Sx X509 Key Algorithms Format . +.Nm sshd +use the first listed for +.Dq rsa +or +.Dq dsa +key in signing and +accept all listed. +.Pp +The default for certificates with RSA key is: +.Bl -item -offset indent -compact +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-rsa , Ar rsa-md5 +.Sm on +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-rsa , Ar rsa-sha1 +.Sm on +.El +.Pp +The default for certificates with DSA key is: +.Bl -item -offset indent -compact +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-dss , Ar dss-asn1 +.Sm on +.It +.Cm X509KeyAlgorithm +.Sm off +.Ar x509v3-sign-dss , Ar dss-raw +.Sm on +.El +.It Cm X509rsaSigType +Deprecated option replaced by X509KeyAlgorithm. .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 @@ -807,6 +1031,43 @@ .It 1h30m 1 hour 30 minutes (90 minutes) .El +.Ss X509 Key Algorithms Format +.Nm sshd +command-line arguments and configuration file options that specify +.Sq X509 Key Algorithms +expressed using a sequence of the form: +.Sm off +.Ar key-type-name , Ar digest-name +.Op Ar \&, signature-identifier , +.Sm on +where +.Ar key-type-name +is key type name, +.Ar digest-name +is +.Bl -tag -compact -offset indent +.It Cm rsa-md5 +: RSA key and signature using the MD5 hash; +.It Cm rsa-sha1 +: RSA key and signature using the SHA-1 hash; +.It Cm dss-asn1 +: DSA key and signature as specified in +.Dq RFC3279 +; +.It Cm dss-raw +: DSA key and signature in +.Dq ssh-dss +format specified in +.Dq SecSH transport +draft . +.El +and optional +.Ar signature-identifier . +When +.Ar signature-identifier +is omited +.Ar key-type-name +is used as identifier. .Sh FILES .Bl -tag -width Ds .It Pa /etc/ssh/sshd_config @@ -828,3 +1089,4 @@ protocol versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support for privilege separation. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/ssh-keygen.0 openssh-4.2p1+x509-5.5/ssh-keygen.0 --- openssh-4.2p1/ssh-keygen.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keygen.0 2006-04-26 00:05:18.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-KEYGEN(1) OpenBSD Reference Manual SSH-KEYGEN(1) +SSH-KEYGEN(1) System General Commands Manual SSH-KEYGEN(1) NAME ssh-keygen - authentication key generation, management and conversion @@ -20,8 +20,8 @@ ssh-keygen -U reader [-f input_keyfile] ssh-keygen -r hostname [-f input_keyfile] [-g] ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point] - ssh-keygen -T output_file -f input_file [-v] [-a num_trials] [-W - generator] + ssh-keygen -T output_file -f input_file [-v] [-a num_trials] + [-W generator] DESCRIPTION ssh-keygen generates, manages and converts authentication keys for @@ -42,14 +42,14 @@ name but ``.pub'' appended. The program also asks for a passphrase. The passphrase may be empty to indicate no passphrase (host keys must have an empty passphrase), or it may be a string of arbitrary length. A - passphrase is similar to a password, except it can be a phrase with a se- - ries of words, punctuation, numbers, whitespace, or any string of charac- - ters you want. Good passphrases are 10-30 characters long, are not sim- - ple sentences or otherwise easily guessable (English prose has only 1-2 - bits of entropy per character, and provides very bad passphrases), and - contain a mix of upper and lowercase letters, numbers, and non-alphanu- - meric characters. The passphrase can be changed later by using the -p - option. + passphrase is similar to a password, except it can be a phrase with a + series of words, punctuation, numbers, whitespace, or any string of char- + acters you want. Good passphrases are 10-30 characters long, are not + simple sentences or otherwise easily guessable (English prose has only + 1-2 bits of entropy per character, and provides very bad passphrases), + and contain a mix of upper and lowercase letters, numbers, and non- + alphanumeric characters. The passphrase can be changed later by using + the -p option. There is no way to recover a lost passphrase. If the passphrase is lost or forgotten, a new key must be generated and copied to the corresponding @@ -110,8 +110,8 @@ -g Use generic DNS format when printing fingerprint resource records using the -r command. - -H Hash a known_hosts file. This replaces all hostnames and ad- - dresses with hashed representations within the specified file; + -H Hash a known_hosts file. This replaces all hostnames and + addresses with hashed representations within the specified file; the original content is moved to a file with a .old suffix. These hashes may be used normally by ssh and sshd, but they do not reveal identifying information should the file's contents be @@ -128,6 +128,8 @@ -l Show fingerprint of specified public key file. Private RSA1 keys are also supported. For RSA and DSA keys ssh-keygen tries to find the matching public key file and prints its fingerprint. + When identity contain X.509 certificate its prints certificate + fingerprint. -M memory Specify the amount of memory to use (in megabytes) when generat- @@ -153,7 +155,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. -S start Specify start point (in hex) when generating candidate moduli for @@ -186,9 +189,9 @@ MODULI GENERATION ssh-keygen may be used to generate groups for the Diffie-Hellman Group Exchange (DH-GEX) protocol. Generating these groups is a two-step pro- - cess: first, candidate primes are generated using a fast, but memory in- - tensive process. These candidate primes are then tested for suitability - (a CPU-intensive process). + cess: first, candidate primes are generated using a fast, but memory + intensive process. These candidate primes are then tested for suitabil- + ity (a CPU-intensive process). Generation of primes is performed using the -G option. The desired length of the primes may be specified by the -b option. For example: @@ -219,8 +222,8 @@ FILES ~/.ssh/identity Contains the protocol version 1 RSA authentication identity of - the user. This file should not be readable by anyone but the us- - er. It is possible to specify a passphrase when generating the + the user. This file should not be readable by anyone but the + user. It is possible to specify a passphrase when generating the key; that passphrase will be used to encrypt the private part of this file using 3DES. This file is not automatically accessed by ssh-keygen but it is offered as the default file for the private @@ -235,35 +238,51 @@ ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of - the user. This file should not be readable by anyone but the us- - er. It is possible to specify a passphrase when generating the - key; that passphrase will be used to encrypt the private part of - this file using 3DES. This file is not automatically accessed by - ssh-keygen but it is offered as the default file for the private - key. ssh(1) will read this file when a login attempt is made. + the user. It is possible to contain private key followed by + X.509 certificate that match it. This file should not be read- + able by anyone but the user. It is possible to specify a + passphrase when generating the key; that passphrase will be used + to encrypt the private part of this file using 3DES. This file + is not automatically accessed by ssh-keygen but it is offered as + the default file for the private key. ssh(1) will read this file + when a login attempt is made. ~/.ssh/id_dsa.pub Contains the protocol version 2 DSA public key for authentica- tion. The contents of this file should be added to ~/.ssh/authorized_keys on all machines where the user wishes to log in using public key authentication. There is no need to keep - the contents of this file secret. + the contents of this file secret. When file ~/.ssh/id_dsa con- + tain DSA private key followed by X.509 certificate this file must + contain that certificate! Use ssh-keygen with option -y to + regenerate its content. Note in case with X.509 certificate you + can append content to ~/.ssh/authorized_keys or to add certifi- + cate ``Distinguished Name'' / ``Subject'' in corresponding format + to ``authorized keys'' file. See sshd(8). ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of - the user. This file should not be readable by anyone but the us- - er. It is possible to specify a passphrase when generating the - key; that passphrase will be used to encrypt the private part of - this file using 3DES. This file is not automatically accessed by - ssh-keygen but it is offered as the default file for the private - key. ssh(1) will read this file when a login attempt is made. + the user. It is possible to contain private key followed by + X.509 certificate that match it. This file should not be read- + able by anyone but the user. It is possible to specify a + passphrase when generating the key; that passphrase will be used + to encrypt the private part of this file using 3DES. This file + is not automatically accessed by ssh-keygen but it is offered as + the default file for the private key. ssh(1) will read this file + when a login attempt is made. ~/.ssh/id_rsa.pub Contains the protocol version 2 RSA public key for authentica- tion. The contents of this file should be added to ~/.ssh/authorized_keys on all machines where the user wishes to log in using public key authentication. There is no need to keep - the contents of this file secret. + the contents of this file secret. When file ~/.ssh/id_rsa con- + tain RSA private key followed by X.509 certificate this file must + contain that certificate! Use ssh-keygen with option -y to + regenerate its content. Note in case with X.509 certificate you + can append content to ~/.ssh/authorized_keys or to add certifi- + cate ``Distinguished Name'' / ``Subject'' in corresponding format + to ``authorized keys'' file. See sshd(8). /etc/moduli Contains Diffie-Hellman groups used for DH-GEX. The file format @@ -278,8 +297,9 @@ AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo - de Raadt and Dug Song removed many bugs, re-added newer features and - created OpenSSH. Markus Friedl contributed the support for SSH protocol - versions 1.5 and 2.0. + 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 X.509 cer- + tificates. -OpenBSD 3.8 September 25, 1999 5 +BSD September 25, 1999 BSD diff -ruN openssh-4.2p1/ssh-keygen.1 openssh-4.2p1+x509-5.5/ssh-keygen.1 --- openssh-4.2p1/ssh-keygen.1 2005-06-16 06:19:06.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keygen.1 2006-01-15 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.69 2005/06/08 03:50:00 djm Exp $ +.\" $OpenBSD$ .\" .\" -*- nroff -*- .\" @@ -16,6 +16,7 @@ .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" Copyright (c) 2002 Roumen Petrov. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -259,6 +260,7 @@ For RSA and DSA keys .Nm tries to find the matching public key file and prints its fingerprint. +When identity contain X.509 certificate its prints certificate fingerprint. .It Fl M Ar memory Specify the amount of memory to use (in megabytes) when generating candidate moduli for DH-GEX. @@ -291,6 +293,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. .It Fl S Ar start Specify start point (in hex) when generating candidate moduli for DH-GEX. .It Fl T Ar output_file @@ -401,6 +404,8 @@ There is no need to keep the contents of this file secret. .It Pa ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of the user. +It is possible to contain private key +followed by X.509 certificate that match it. This file should not be readable by anyone but the user. It is possible to specify a passphrase when generating the key; that passphrase will be @@ -417,8 +422,27 @@ on all machines where the user wishes to log in using public key authentication. There is no need to keep the contents of this file secret. +When file +.Pa ~/.ssh/id_dsa +contain DSA private key followed by X.509 certificate +this file must contain that certificate! +Use +.Nm +with option -y to regenerate its content. +Note in case with X.509 certificate you can append content to +.Pa ~/.ssh/authorized_keys +or to add certificate +.Dq Distinguished Name +/ +.Dq Subject +in corresponding format to +.Dq authorized keys +file. See +.Xr sshd 8 . .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. +It is possible to contain private key +followed by X.509 certificate that match it. This file should not be readable by anyone but the user. It is possible to specify a passphrase when generating the key; that passphrase will be @@ -435,6 +459,23 @@ on all machines where the user wishes to log in using public key authentication. There is no need to keep the contents of this file secret. +When file +.Pa ~/.ssh/id_rsa +contain RSA private key followed by X.509 certificate +this file must contain that certificate! +Use +.Nm +with option -y to regenerate its content. +Note in case with X.509 certificate you can append content to +.Pa ~/.ssh/authorized_keys +or to add certificate +.Dq Distinguished Name +/ +.Dq Subject +in corresponding format to +.Dq authorized keys +file. See +.Xr sshd 8 . .It Pa /etc/moduli Contains Diffie-Hellman groups used for DH-GEX. The file format is described in @@ -463,3 +504,4 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Roumen Petrov contributed support for X.509 certificates. diff -ruN openssh-4.2p1/ssh-keygen.c openssh-4.2p1+x509-5.5/ssh-keygen.c --- openssh-4.2p1/ssh-keygen.c 2005-07-17 10:22:46.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keygen.c 2006-01-15 09:06:01.000000000 +0200 @@ -9,10 +9,33 @@ * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". + * + * 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: + * 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" -RCSID("$OpenBSD: ssh-keygen.c,v 1.128 2005/07/17 07:17:55 djm Exp $"); +RCSID("$OpenBSD$"); #include #include @@ -29,6 +52,7 @@ #include "misc.h" #include "match.h" #include "hostfile.h" +#include "ssh-xkalg.h" #ifdef SMARTCARD #include "scard.h" @@ -1021,6 +1045,7 @@ __progname = ssh_get_progname(av[0]); SSLeay_add_all_algorithms(); + fill_default_xkalg(); log_init(av[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); init_rng(); diff -ruN openssh-4.2p1/ssh-keyscan.0 openssh-4.2p1+x509-5.5/ssh-keyscan.0 --- openssh-4.2p1/ssh-keyscan.0 2005-09-01 12:15:25.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keyscan.0 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-KEYSCAN(1) OpenBSD Reference Manual SSH-KEYSCAN(1) +SSH-KEYSCAN(1) System General Commands Manual SSH-KEYSCAN(1) NAME ssh-keyscan - gather ssh public keys @@ -42,13 +42,14 @@ Set the timeout for connection attempts. If timeout seconds have elapsed since a connection was initiated to a host or since the last time anything was read from that host, then the connection - is closed and the host in question considered unavailable. De- - fault is 5 seconds. + is closed and the host in question considered unavailable. + Default is 5 seconds. -t type Specifies the type of the key to fetch from the scanned hosts. The possible values are ``rsa1'' for protocol version 1 and - ``rsa'' or ``dsa'' for protocol version 2. Multiple values may + ``ssh-rsa'' , ``ssh-dss'' , ``x509v3-sign-rsa'' or + ``x509v3-sign-dss'' for protocol version 2. Multiple values may be specified by separating them with commas. The default is ``rsa1''. @@ -59,8 +60,8 @@ If a ssh_known_hosts file is constructed using ssh-keyscan without veri- fying the keys, users will be vulnerable to man in the middle attacks. On the other hand, if the security model allows such a risk, ssh-keyscan - can help in the detection of tampered keyfiles or man in the middle at- - tacks which have begun after the ssh_known_hosts file was created. + can help in the detection of tampered keyfiles or man in the middle + attacks which have begun after the ssh_known_hosts file was created. FILES Input format: @@ -77,6 +78,12 @@ Where keytype is either ``ssh-rsa'' or ``ssh-dss''. + Output format for rsa and dsa keys with X.509 certificates: + + host-or-namelist keytype distinguished-name + + Where keytype is either ``x509v3-sign-rsa'' or ``x509v3-sign-dss''. + /etc/ssh/ssh_known_hosts EXAMPLES @@ -87,7 +94,7 @@ Find all hosts from the file ssh_hosts which have new or different keys from those in the sorted file ssh_known_hosts: - $ ssh-keyscan -t rsa,dsa -f ssh_hosts | \ + $ ssh-keyscan -t x509v3-sign-rsa,x509v3-sign-dss,rsa,dsa -f ssh_hosts | \ sort -u - ssh_known_hosts | diff ssh_known_hosts - SEE ALSO @@ -96,7 +103,7 @@ AUTHORS David Mazieres wrote the initial version, and Wayne Davison added support for protocol - version 2. + version 2. Roumen Petrov contributed support for X.509 certificates. BUGS It generates "Connection closed by remote host" messages on the consoles @@ -104,4 +111,4 @@ This is because it opens a connection to the ssh port, reads the public key, and drops the connection as soon as it gets the key. -OpenBSD 3.8 January 1, 1996 2 +BSD January 1, 1996 BSD diff -ruN openssh-4.2p1/ssh-keyscan.1 openssh-4.2p1+x509-5.5/ssh-keyscan.1 --- openssh-4.2p1/ssh-keyscan.1 2005-03-02 03:04:01.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-keyscan.1 2006-04-26 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.20 2005/03/01 15:47:14 jmc Exp $ +.\" $OpenBSD$ .\" .\" Copyright 1995, 1996 by David Mazieres . .\" @@ -6,6 +6,29 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" +.\" X.509 certificates support, +.\" 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 +.\" 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. +.\" .Dd January 1, 1996 .Dt SSH-KEYSCAN 1 .Os @@ -88,9 +111,13 @@ The possible values are .Dq rsa1 for protocol version 1 and -.Dq rsa +.Dq ssh-rsa +, +.Dq ssh-dss +, +.Dq x509v3-sign-rsa or -.Dq dsa +.Dq x509v3-sign-dss for protocol version 2. Multiple values may be specified by separating them with commas. The default is @@ -134,6 +161,18 @@ or .Dq ssh-dss . .Pp +.Pa Output format for rsa and dsa keys with X.509 certificates: +.Bd -literal +host-or-namelist keytype distinguished-name +.Ed +.Pp +Where +.Pa keytype +is either +.Dq x509v3-sign-rsa +or +.Dq x509v3-sign-dss . +.Pp .Pa /etc/ssh/ssh_known_hosts .Sh EXAMPLES Print the @@ -149,7 +188,7 @@ which have new or different keys from those in the sorted file .Pa ssh_known_hosts : .Bd -literal -$ ssh-keyscan -t rsa,dsa -f ssh_hosts | \e +$ ssh-keyscan -t x509v3-sign-rsa,x509v3-sign-dss,rsa,dsa -f ssh_hosts | \e sort -u - ssh_known_hosts | diff ssh_known_hosts - .Ed .Sh SEE ALSO @@ -160,6 +199,7 @@ wrote the initial version, and .An Wayne Davison Aq wayned@users.sourceforge.net added support for protocol version 2. +Roumen Petrov contributed support for X.509 certificates. .Sh BUGS It generates "Connection closed by remote host" messages on the consoles of all the machines it scans if the server is older than version 2.9. diff -ruN openssh-4.2p1/ssh-keyscan.c openssh-4.2p1+x509-5.5/ssh-keyscan.c --- openssh-4.2p1/ssh-keyscan.c 2005-06-17 05:59:35.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keyscan.c 2006-01-15 09:06:01.000000000 +0200 @@ -4,10 +4,33 @@ * Modification and redistribution in source and binary forms is * permitted provided that due credit is given to the author and the * OpenBSD project by leaving this copyright notice intact. + * + * X.509 certificates support, + * 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 + * 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" -RCSID("$OpenBSD: ssh-keyscan.c,v 1.55 2005/06/17 02:44:33 djm Exp $"); +RCSID("$OpenBSD$"); #include "openbsd-compat/sys-queue.h" @@ -18,6 +41,8 @@ #include "ssh.h" #include "ssh1.h" #include "key.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" #include "kex.h" #include "compat.h" #include "myproposal.h" @@ -36,11 +61,7 @@ int ssh_port = SSH_DEFAULT_PORT; -#define KT_RSA1 1 -#define KT_DSA 2 -#define KT_RSA 4 - -int get_keytypes = KT_RSA1; /* Get only RSA1 keys by default */ +char* get_keynames = "rsa1"; /* Get only RSA1 keys by default */ int hash_hosts = 0; /* Hash hostname on output */ @@ -74,7 +95,7 @@ int c_plen; /* Packet length field for ssh packet */ int c_len; /* Total bytes which must be read. */ int c_off; /* Length of data read so far. */ - int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ + const char *c_keyname; char *c_namebase; /* Address to free for c_name and c_namelist */ char *c_name; /* Hostname of connection for errors */ char *c_namelist; /* Pointer to other possible addresses */ @@ -344,8 +365,7 @@ packet_set_connection(c->c_fd, c->c_fd); enable_compat20(); - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? - "ssh-dss": "ssh-rsa"; + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = (char*)c->c_keyname; c->c_kex = kex_setup(myproposal); c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; @@ -377,7 +397,16 @@ fatal("host_hash failed"); fprintf(stdout, "%s ", host); +#ifndef SSH_X509STORE_DISABLED + if ((key->type == KEY_X509_RSA) || (key->type == KEY_X509_DSA)) { + /* key_write will print x509 certificate in blob format :-( */ + x509key_write_subject2(key, c->c_keyname, stdout); + } else { +#endif /*ndef SSH_X509STORE_DISABLED*/ key_write(key, stdout); +#ifndef SSH_X509STORE_DISABLED + } +#endif /*ndef SSH_X509STORE_DISABLED*/ fputs("\n", stdout); } @@ -415,7 +444,7 @@ } static int -conalloc(char *iname, char *oname, int keytype) +conalloc(char *iname, char *oname, const char *keyname) { char *namebase, *name, *namelist; int s; @@ -444,7 +473,7 @@ fdcon[s].c_data = (char *) &fdcon[s].c_plen; fdcon[s].c_len = 4; fdcon[s].c_off = 0; - fdcon[s].c_keytype = keytype; + fdcon[s].c_keyname = keyname; gettimeofday(&fdcon[s].c_tv, NULL); fdcon[s].c_tv.tv_sec += timeout; TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); @@ -464,7 +493,7 @@ if (fdcon[s].c_status == CS_KEYS) xfree(fdcon[s].c_data); fdcon[s].c_status = CS_UNUSED; - fdcon[s].c_keytype = 0; + fdcon[s].c_keyname = NULL; TAILQ_REMOVE(&tq, &fdcon[s], c_link); FD_CLR(s, read_wait); ncon--; @@ -485,7 +514,7 @@ con *c = &fdcon[s]; int ret; - ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype); + ret = conalloc(c->c_namelist, c->c_output_name, c->c_keyname); confree(s); return (ret); } @@ -498,6 +527,7 @@ char remote_version[sizeof buf]; size_t bufsiz; con *c = &fdcon[s]; + int rsa1key; bufsiz = sizeof(buf); cp = buf; @@ -531,7 +561,8 @@ compat_datafellows(remote_version); else datafellows = 0; - if (c->c_keytype != KT_RSA1) { + rsa1key = (strcmp(c->c_keyname, "rsa1") == 0); + if (!rsa1key) { if (!ssh2_capable(remote_major, remote_minor)) { debug("%s doesn't support ssh2", c->c_name); confree(s); @@ -544,8 +575,8 @@ } fprintf(stderr, "# %s %s\n", c->c_name, chop(buf)); n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n", - c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2, - c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2); + rsa1key ? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2, + rsa1key ? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2); if (n < 0 || (size_t)n >= sizeof(buf)) { error("snprintf: buffer too small"); confree(s); @@ -556,7 +587,7 @@ confree(s); return; } - if (c->c_keytype != KT_RSA1) { + if (!rsa1key) { keyprint(c, keygrab_ssh2(c)); confree(s); return; @@ -661,16 +692,18 @@ do_host(char *host) { char *name = strnnsep(&host, " \t\n"); - int j; + const char *keyname; if (name == NULL) return; - for (j = KT_RSA1; j <= KT_RSA; j *= 2) { - if (get_keytypes & j) { - while (ncon >= MAXCON) - conloop(); - conalloc(name, *host ? host : name, j); - } + for ( + keyname = strtok(get_keynames, ","); + keyname != NULL; + keyname = strtok(NULL, ",") + ) { + while (ncon >= MAXCON) + conloop(); + conalloc(name, *host ? host : name, keyname); } } @@ -715,6 +748,7 @@ if (argc <= 1) usage(); + fill_default_xkalg(); while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) { switch (opt) { case 'H': @@ -750,23 +784,12 @@ argv[fopt_count++] = optarg; break; case 't': - get_keytypes = 0; + get_keynames = xstrdup(optarg); tname = strtok(optarg, ","); while (tname) { int type = key_type_from_name(tname); - switch (type) { - case KEY_RSA1: - get_keytypes |= KT_RSA1; - break; - case KEY_DSA: - get_keytypes |= KT_DSA; - break; - case KEY_RSA: - get_keytypes |= KT_RSA; - break; - case KEY_UNSPEC: + if (type == KEY_UNSPEC) fatal("unknown key type %s", tname); - } tname = strtok(NULL, ","); } break; diff -ruN openssh-4.2p1/ssh-keysign.0 openssh-4.2p1+x509-5.5/ssh-keysign.0 --- openssh-4.2p1/ssh-keysign.0 2005-09-01 12:15:26.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keysign.0 2006-04-26 00:05:20.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-KEYSIGN(8) OpenBSD System Manager's Manual SSH-KEYSIGN(8) +SSH-KEYSIGN(8) System Manager's Manual SSH-KEYSIGN(8) NAME ssh-keysign - ssh helper program for hostbased authentication @@ -28,7 +28,9 @@ generate the digital signature. They should be owned by root, readable only by root, and not accessible to others. Since they are readable only by root, ssh-keysign must be set-uid root if - hostbased authentication is used. + hostbased authentication is used. It is possible host key to + contain private parts followed by X.509 certificate that match + it. SEE ALSO ssh(1), ssh-keygen(1), ssh_config(5), sshd(8) @@ -39,4 +41,4 @@ AUTHORS Markus Friedl -OpenBSD 3.8 May 24, 2002 1 +BSD May 24, 2002 BSD diff -ruN openssh-4.2p1/ssh-keysign.8 openssh-4.2p1+x509-5.5/ssh-keysign.8 --- openssh-4.2p1/ssh-keysign.8 2003-06-11 15:04:39.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-keysign.8 2005-09-02 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.7 2003/06/10 09:12:11 jmc Exp $ +.\" $OpenBSD$ .\" .\" Copyright (c) 2002 Markus Friedl. All rights reserved. .\" @@ -68,6 +68,8 @@ Since they are readable only by root, .Nm must be set-uid root if hostbased authentication is used. +It is possible host key to contain private parts +followed by X.509 certificate that match it. .El .Sh SEE ALSO .Xr ssh 1 , diff -ruN openssh-4.2p1/ssh-ocsp.c openssh-4.2p1+x509-5.5/ssh-ocsp.c --- openssh-4.2p1/ssh-ocsp.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-ocsp.c 2006-05-18 21:02:45.000000000 +0300 @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 2004-2006 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 "x509store.h" +#ifndef SSH_OCSP_ENABLED +# include "error: OCSP is disabled" +#endif + +#if 1 +# /* not yet fully implemented */ +# define SSH_WITH_SSLOCSP +#endif + +#include "xmalloc.h" +#include "log.h" +#include +#include +#include +#ifdef SSH_WITH_SSLOCSP +# include +#endif + + +static VAOptions va = { SSHVA_NONE, NULL, NULL }; + +typedef struct va_type_map_s va_type_map; +struct va_type_map_s { + int id; + const char* code; +}; + +static va_type_map sshva_type_map[] = { + { SSHVA_NONE , "none" }, + { SSHVA_OCSP_CERT, "ocspcert" }, + { SSHVA_OCSP_SPEC, "ocspspec" }, +}; + + +int +ssh_get_default_vatype(void) { + return(SSHVA_NONE); +} + + +int +ssh_get_vatype_s(const char* type) { + int k, n; + + if (type == NULL) return(-1); + + n = sizeof(sshva_type_map) / sizeof(sshva_type_map[0]); + for (k = 0; k < n; k++) { + va_type_map *p = sshva_type_map + k; + if (strcasecmp(type, p->code) == 0) return(p->id); + } + + return(-1); +} + + +static void +ssh_set_vatype(int type) { + switch (type) { + case SSHVA_NONE: + case SSHVA_OCSP_CERT: + case SSHVA_OCSP_SPEC: + va.type = type; + break; + default: + fatal("ssh_set_vatype: invalid type %d", type); + break; + } +} + + +void +ssh_set_validator(const VAOptions *_va) { + if (va.certificate_file != NULL) { + xfree((void*)va.certificate_file); + va.certificate_file = NULL; + } + if (va.responder_url != NULL) { + xfree((void*)va.responder_url); + va.responder_url = NULL; + } + if (_va == NULL) { + debug("ssh_set_validator: NULL options - set vatype to none"); + ssh_set_vatype(SSHVA_NONE); + return; + } + + ssh_set_vatype(_va->type); /*fatal on error*/ + if (_va->certificate_file != NULL) { + switch(va.type) { + case SSHVA_NONE: + case SSHVA_OCSP_CERT: + debug("ssh_set_validator: ignore certificate file"); + break; + case SSHVA_OCSP_SPEC: + va.certificate_file = xstrdup(_va->certificate_file); /*fatal on error*/ + break; + } + } + switch(va.type) { + case SSHVA_NONE: + case SSHVA_OCSP_CERT: + debug("ssh_set_validator: ignore responder url"); + break; + case SSHVA_OCSP_SPEC: + if (_va->responder_url == NULL) { + fatal("ssh_set_validator: responder url is mandatory"); + } + va.responder_url = xstrdup(_va->responder_url); /*fatal on error*/ + break; + } +} + + +static char* +openssl_errormsg(char *buf, size_t len) { + ERR_error_string_n(ERR_get_error(), buf, len); + + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + return(buf); +} + + +static void +openssl_error(const char *ssh_method, const char *openssl_method) { + char buf[512]; + + ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + + error("%.128s: %.128s fail with errormsg='%.*s'" + , ssh_method + , openssl_method + , (int) sizeof(buf), buf); +} + + +static char* +ssh_ASN1_GENERALIZEDTIME_2_string(ASN1_GENERALIZEDTIME *asn1_time) { + BIO *bio; + int k; + char *p = NULL; + + if (asn1_time == NULL) { + error("ssh_ASN1_GENERALIZEDTIME_2_string: asn1_time is NULL"); + return(NULL); + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + error("ssh_ASN1_GENERALIZEDTIME_2_string: BIO_new fail"); + return(NULL); + } + + ASN1_GENERALIZEDTIME_print(bio, asn1_time); + BIO_flush(bio); + + k = BIO_pending(bio); + p = xmalloc(k + 1); /*fatal on error*/ + k = BIO_read(bio, p, k); + p[k] = '\0'; + BIO_free_all(bio); + return(p); +} + + +static STACK_OF(X509)* +ssh_load_x509certs(const char *certs_file, const char* certs_descrip) { + STACK_OF(X509) *ret_certs = NULL; + BIO *fbio = NULL; + + if (certs_file == NULL) { + error("ssh_load_x509certs: file is NULL"); + goto exit; + } + + ret_certs = sk_X509_new_null(); + if (ret_certs == NULL) { + error("ssh_load_x509certs: sk_X509_new_null fail"); + goto exit; + } + + fbio = BIO_new(BIO_s_file()); + if (fbio == NULL) { + error("ssh_load_x509certs: BIO_new fail"); + goto exit; + } + + if (BIO_read_filename(fbio, certs_file) <= 0) { + openssl_error("ssh_load_x509certs", "BIO_read_filename"); + logit("ssh_load_x509certs:" + " description/filename='%.512s'/'%.512s'" + , certs_descrip + , certs_file); + goto exit; + } + + { + int k; + STACK_OF(X509_INFO) *data; + + data = PEM_X509_INFO_read_bio(fbio, NULL, NULL, NULL); + if (data == NULL) { + error("ssh_load_x509certs: no data."); + goto exit; + } + + for (k = 0; k < sk_X509_INFO_num(data); k++) { + X509_INFO *xi = sk_X509_INFO_value(data, k); + if (xi->x509) { + sk_X509_push(ret_certs, xi->x509); + xi->x509 = NULL; + } + } + sk_X509_INFO_pop_free(data, X509_INFO_free); + } + +exit: + if (fbio != NULL) BIO_free_all(fbio); + if (ret_certs != NULL) { + debug3("ssh_load_x509certs: return %d certs", (int)sk_X509_num(ret_certs)); + } else { + debug("ssh_load_x509certs: return NULL"); + } + return(ret_certs); +} + + +static int/*bool*/ +ssh_ocspreq_addcert( + X509 *cert, + X509_STORE* x509store, + OCSP_REQUEST *req, + STACK_OF(OCSP_CERTID) *ids, + STACK *subjs +) { + X509 *issuer = NULL; + OCSP_CERTID *id = NULL; + char *subj = NULL; + + if (cert == NULL) { + error("ssh_ocspreq_addcert: cert is NULL"); + return(0); + } + if (x509store == NULL) { + error("ssh_ocspreq_addcert: x509store is NULL"); + return(0); + } + if (req == NULL) { + error("ssh_ocspreq_addcert: req is NULL"); + return(0); + } + if (ids == NULL) { + error("ssh_ocspreq_addcert: ids is NULL"); + return(0); + } + if (subjs == NULL) { + error("ssh_ocspreq_addcert: subjs is NULL"); + return(0); + } + + { + X509_OBJECT xobj; + memset(&xobj, 0, sizeof(xobj)); + if (ssh_x509store_lookup(x509store, X509_LU_X509, X509_get_issuer_name(cert), &xobj) > 0) { + issuer = xobj.data.x509; + } + X509_OBJECT_free_contents(&xobj); + } + if (issuer == NULL) { + error("ssh_ocspreq_addcert: cannot found issuer certificate"); + return(0); + } + + id = OCSP_cert_to_id(NULL, cert, issuer); + if (id == NULL) { + error("ssh_ocspreq_addcert: OCSP_cert_to_id fail"); + return(0); + } + + if (!OCSP_request_add0_id(req, id)) { + error("ssh_ocspreq_addcert: OCSP_request_add0_id fail"); + return(0); + } + if (!sk_OCSP_CERTID_push(ids, id)) { + error("ssh_ocspreq_addcert: sk_OCSP_CERTID_push fail"); + return(0); + } + subj = xmalloc(X509_NAME_MAXLEN); /*fatal on error*/ + X509_NAME_oneline(X509_get_subject_name(cert), subj, X509_NAME_MAXLEN); + if (!sk_push(subjs, subj)) { + error("ssh_ocspreq_addcert: sk_push(..., subj) fail"); + return(0); + } + + return(1); +} + + +struct ssh_ocsp_conn_s { + const char *url; + +#ifdef SSH_WITH_SSLOCSP + int use_ssl; +#endif + /*pointers inside data buffer*/ + /*const*/ char *host; + const char *port; + /*const*/ char *path; + + /*data buffer to hold all connection info*/ + char *data; +}; + +typedef struct ssh_ocsp_conn_s ssh_ocsp_conn; + + +static void +ssh_ocsp_conn_free(ssh_ocsp_conn **pconn) { + ssh_ocsp_conn *conn = *pconn; + + if (conn == NULL) return; + *pconn = NULL; + + if (conn->data != NULL) xfree(conn->data); + if (conn->url != NULL) xfree((void*)conn->url ); + xfree(conn); +} + + +static int/*bool*/ +ssh_ocsp_set_protocol(ssh_ocsp_conn *conn, const char *protocol) { + if (strcmp(protocol, "http") == 0) { +#ifdef SSH_WITH_SSLOCSP + conn->use_ssl = 0; +#endif + return(1); + } + +#ifdef SSH_WITH_SSLOCSP + if (strcmp(protocol, "https") == 0) { + conn->use_ssl = 1; + return(1); + } +#endif + +#ifdef SSH_WITH_SSLOCSP + conn->use_ssl = -1; +#endif + return(0); +} + + +static ssh_ocsp_conn* +ssh_ocsp_conn_new(const char *url) { + ssh_ocsp_conn *conn = NULL; + char *p = NULL; + char *q = NULL; + + if (url == NULL) { + error("ssh_ocsp_conn_new: url is NULL"); + return(NULL); + } + + conn = xmalloc(sizeof(*conn)); /*fatal on error*/ + memset(conn, 0, sizeof(*conn)); + + conn->url = xstrdup(url); /*fatal on error*/ + conn->data = xstrdup(url); /*fatal on error*/ + + /* chech for protocol */ + p = conn->data; + q = strchr(p, ':'); + if (q == NULL) goto error; + *q = '\x0'; + + if (!ssh_ocsp_set_protocol(conn, p)) { + error("ssh_ocsp_conn_new:" + " unsupported protocol '%.16s'" + , p); + goto error; + } + + p = q; + if (*++p != '/') { /*this symbol is inside data */ + error("ssh_ocsp_conn_new: expected first slash," + " got char with code %d" + , (int)*p); + goto error; + } + if (*++p != '/') { /*this symbol is inside data */ + error("ssh_ocsp_conn_new: expected second slash," + " got char with code %d" + , (int)*p); + goto error; + } + + /* chech for host and port */ + if (*++p == '\x0') { + error("ssh_ocsp_conn_new: missing host in url '%.512s'", url); + goto error; + } + conn->host = p; + q = strchr(p, '/'); + if (q != NULL) { + *q = '\x0'; + /* q+1 might point to path */ + } + /*else q is NULL !!!*/ + + /* chech for port */ + p = strrchr(conn->host, ':'); + if (p != NULL) { + *p = '\x0'; + if (*++p != '\x0') conn->port = p; + } + if (conn->port == NULL) { +#ifdef SSH_WITH_SSLOCSP + conn->port = conn->use_ssl ? "443" : "80"; +#else + conn->port = "80"; +#endif + } + + /* chech for path */ + p = q; + if (p == NULL) goto exit; + if (*++p == '\x0') goto exit; + conn->path = p; + +exit: + return(conn); +error: + ssh_ocsp_conn_free(&conn); + goto exit; +} + + +static OCSP_RESPONSE* +ssh_ocsp_get_response(const ssh_ocsp_conn *conn, OCSP_REQUEST *req) { + OCSP_RESPONSE *resp = NULL; + BIO *bio_conn = NULL; +#ifdef SSH_WITH_SSLOCSP + SSL_CTX *ctx = NULL; +#endif + + if (conn == NULL) { + error("ssh_ocsp_get_response: conn is NULL"); + return(NULL); + } + if (req == NULL) { + error("ssh_ocsp_get_response: req is NULL"); + return(NULL); + } + +#ifndef OPENSSL_NO_SOCK + bio_conn = BIO_new_connect(conn->host); + if (bio_conn == NULL) { + openssl_error("ssh_ocsp_get_response", "BIO_new_connect"); + goto exit; + } +#else + error("ssh_ocsp_get_response: sockets are not supported in OpenSSL"); + goto exit; +#endif + if (conn->port != NULL) { + BIO_set_conn_port(bio_conn, conn->port); + } + +#ifdef SSH_WITH_SSLOCSP + if (conn->use_ssl == 1) { + BIO *bio_sslconn; +#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) + ctx = SSL_CTX_new(SSLv23_client_method()); +#elif !defined(OPENSSL_NO_SSL3) + ctx = SSL_CTX_new(SSLv3_client_method()); +#elif !defined(OPENSSL_NO_SSL2) + ctx = SSL_CTX_new(SSLv2_client_method()); +#else + error("ssh_ocsp_get_response: SSL is disabled"); + goto exit; +#endif + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + bio_sslconn = BIO_new_ssl(ctx, 1); + bio_conn = BIO_push(bio_sslconn, bio_conn); + } +#endif /*def SSH_WITH_SSLOCSP*/ + + if (BIO_do_connect(bio_conn) <= 0) { + openssl_error("ssh_ocsp_get_response", "BIO_do_connect"); + goto exit; + } + + /* + * OCSP_sendreq_bio accpet null as path argument but if path + * is null http request will contain what is incorrect. + */ + resp = OCSP_sendreq_bio(bio_conn, (conn->path ? conn->path : "/") , req); + if (resp == NULL) { + openssl_error("ssh_ocsp_get_response", "OCSP_sendreq_bio"); + } + +exit: + if (bio_conn != NULL) BIO_free_all(bio_conn); +#ifdef SSH_WITH_SSLOCSP + if (ctx != NULL) SSL_CTX_free(ctx); +#endif + + return(resp); +} + + +static OCSP_BASICRESP* +ssh_ocsp_get_basicresp( + OCSP_REQUEST *req, + OCSP_RESPONSE *resp, + STACK_OF(X509) *vacrts, + X509_STORE *x509store +) { + OCSP_BASICRESP *br = NULL; + unsigned long basic_verify_flags = 0/*NO:OCSP_NOEXPLICIT*/; + int flag; + + if (req == NULL) { + error("ssh_ocsp_get_basicresp: req is NULL"); + return(NULL); + } + if (resp == NULL) { + error("ssh_ocsp_get_basicresp: resp is NULL"); + return(NULL); + } + if (x509store == NULL) { + error("ssh_ocsp_get_basicresp: x509store is NULL"); + return(NULL); + } + + br = OCSP_response_get1_basic(resp); + if (br == NULL) { + openssl_error("ssh_ocsp_get_basicresp", "OCSP_response_get1_basic"); + return(NULL); + } + + flag = OCSP_check_nonce(req, br); + if (flag <= 0) { + if (flag == -1) { + logit("ssh_ocsp_get_basicresp: WARNING - no nonce in response"); + } else { + openssl_error("ssh_ocsp_get_basicresp", "OCSP_check_nonce"); + goto error; + } + } + +#ifdef SSHOCSPTEST +{ +int k; +logit("ssh_ocsp_get_basicresp: VA certs num=%d", sk_X509_num(vacrts)); +for (k = 0; k < sk_X509_num(vacrts); k++) { + char buf[X509_NAME_MAXLEN]; + X509 *x = sk_X509_value(vacrts, k); + X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf)); + logit("ssh_ocsp_get_basicresp: VA[%d] subject='%.*s'" + , k + , (int) sizeof(buf), buf); +} +} +#endif /*def SSHOCSPTEST*/ + +/* + * RFC2560: + * ... + * All definitive response messages SHALL be digitally signed. The key + * used to sign the response MUST belong to one of the following: + * + * -- the CA who issued the certificate in question + * -- a Trusted Responder whose public key is trusted by the requester + * -- a CA Designated Responder (Authorized Responder) who holds a + * specially marked certificate issued directly by the CA, indicating + * that the responder may issue OCSP responses for that CA + * ... + * + * TODO: to check OpenSLL implementation + */ + if ((vacrts == NULL) || (sk_X509_num(vacrts) <= 0)) { + flag = -1; + } else { + /* + * With flag OCSP_TRUSTOTHER: + * - we never get error 'without missing ocspsigning + * usage' for VA certificate !!! + * Without flag OCSP_TRUSTOTHER: + * - we can get OCSP_basic_verify error "root ca not trusted" + */ +#if 0 + flag = OCSP_basic_verify(br, vacrts, x509store, basic_verify_flags | OCSP_TRUSTOTHER); +#else + flag = OCSP_basic_verify(br, vacrts, x509store, basic_verify_flags); +#endif + } + if (flag < 0) { + flag = OCSP_basic_verify(br, NULL, x509store, basic_verify_flags); + } + if (flag <= 0) { + openssl_error("ssh_ocsp_get_basicresp", "OCSP_basic_verify"); + logit("ssh_ocsp_get_basicresp: flag=%d", flag); + goto error; + } + + debug3("ssh_ocsp_get_basicresp: OK"); + return(br); + +error: + debug3("ssh_ocsp_get_basicresp: FAIL"); + if (br != NULL) OCSP_BASICRESP_free(br); + return(NULL); +} + + +/* + * Method return value: + * 1 - all cert.-s are good + * -1 - error or at least one cert. with status unknow + * 0 - otherwise, i.e. at least one cert. is revoked and rest are good + */ +static int +ssh_ocsp_check_validity( + OCSP_REQUEST *req, + OCSP_BASICRESP *br, + STACK_OF(OCSP_CERTID) *ids, + STACK *subjs +) { + int ret = 1; + /* Maximum leeway in validity period: default 5 minutes */ + const long nsec = (5 * 60); + const long maxage = -1; + + int k; + int status, reason; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + if (req == NULL) { + error("ssh_ocsp_check_validity: req is NULL"); + return(-1); + } + if (br == NULL) { + error("ssh_ocsp_check_validity: br is NULL"); + return(-1); + } + if (sk_OCSP_CERTID_num(ids) <= 0) { + error("ssh_ocsp_check_validity:" + " number of ids is %d" + , sk_OCSP_CERTID_num(ids)); + return(-1); + } + if (sk_OCSP_CERTID_num(subjs) <= 0) { + error("ssh_ocsp_check_validity:" + " number of subjs is %d" + , sk_OCSP_CERTID_num(subjs)); + return(-1); + } + if (sk_OCSP_CERTID_num(ids) != sk_OCSP_CERTID_num(subjs)) { + error("ssh_ocsp_check_validity:" + " ids(%d) != subjs(%d)" + , sk_OCSP_CERTID_num(ids) + , sk_OCSP_CERTID_num(subjs)); + return(-1); + } + + for (k = 0; k < sk_OCSP_CERTID_num(ids); k++) { + OCSP_CERTID *id = sk_OCSP_CERTID_value(ids, k); + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char *subject = sk_value(subjs, k); + debug3("ssh_ocsp_check_validity: cert[%d]='%.*s'" + , k + , (int) X509_NAME_MAXLEN, subject); + } + + if (!OCSP_resp_find_status( + br, id, &status, &reason, + &rev, &thisupd, &nextupd) + ) { + ret = -1; + error("ssh_ocsp_check_validity: cannot found status"); + break; + } + + if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { + char ebuf[512]; + ret = -1; + logit("ssh_ocsp_check_validity: " + " WARNING-invalid status time." + " OCSP_check_validity fail with errormsg='%.512s'" + , openssl_errormsg(ebuf, sizeof(ebuf))); + break; + } + debug("ssh_ocsp_check_validity: status=%.32s", OCSP_cert_status_str(status)); + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char *p = ssh_ASN1_GENERALIZEDTIME_2_string(thisupd); + debug3("ssh_ocsp_check_validity: This Update=%.128s", p); + xfree(p); + if (nextupd != NULL) { + p = ssh_ASN1_GENERALIZEDTIME_2_string(nextupd); + debug3("ssh_ocsp_check_validity: Next Update=%.128s", p); + xfree(p); + } + } + + if (status == V_OCSP_CERTSTATUS_GOOD) continue; + + if (status != V_OCSP_CERTSTATUS_REVOKED) { + ret = -1; + error("ssh_ocsp_check_validity: unknow certificate status"); + break; + } + + ret = 0; + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char *p = ssh_ASN1_GENERALIZEDTIME_2_string(rev); + debug3("ssh_ocsp_check_validity: Revocation Time=%.128s", p); + xfree(p); + if (reason != -1) { + debug3("ssh_ocsp_check_validity:" + " Revocation Reason='%.128s'" + , OCSP_crl_reason_str(reason)); + } + } + break; + } + debug3("ssh_ocsp_check_validity: return %d", ret); + return(ret); +} + + +static int +ssh_ocsp_validate2( + X509 *cert, + X509_STORE *x509store, + const ssh_ocsp_conn *ocsp +) { + int ret = -1; + int add_nonce = 0; + + STACK_OF(X509) *vacrts = NULL; + OCSP_REQUEST *req = OCSP_REQUEST_new(); + STACK_OF(OCSP_CERTID) *ids = sk_OCSP_CERTID_new_null(); + STACK *subjs = sk_new_null(); + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *br = NULL; + + if ((va.type == SSHVA_OCSP_SPEC) && + (va.certificate_file != NULL)) { + vacrts = ssh_load_x509certs(va.certificate_file, "'OCSP Responder' trusted certificates"); + if (vacrts == NULL) goto exit; + debug("ssh_ocsp_validate2: VA certs num=%d", sk_X509_num(vacrts)); + } + + if (!ssh_ocspreq_addcert(cert, x509store, req, ids, subjs)) { + goto exit; + } + + if (req && add_nonce) { + OCSP_request_add1_nonce(req, NULL, -1); + } + + resp = ssh_ocsp_get_response(ocsp, req); + if (resp == NULL) goto exit; + + { /*check OCSP response status*/ + int flag = OCSP_response_status(resp); + if (flag != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + error("ssh_ocsp_validate2:" + " responder error=%d(%.256s)" + , flag + , OCSP_response_status_str((long/*???*/)flag)); + goto exit; + } + } + + br = ssh_ocsp_get_basicresp(req, resp, vacrts, x509store); + if (br == NULL) goto exit; + + ret = ssh_ocsp_check_validity(req, br, ids, subjs); + +exit: + if (br != NULL) OCSP_BASICRESP_free(br); + if (resp != NULL) OCSP_RESPONSE_free(resp); + if (subjs != NULL) sk_pop_free(subjs, xfree); + if (ids != NULL) sk_OCSP_CERTID_free(ids); + if (req != NULL) OCSP_REQUEST_free(req); + if (vacrts != NULL) sk_X509_pop_free(vacrts, X509_free); + + return(ret); +} + + +static AUTHORITY_INFO_ACCESS* +ssh_aia_get(X509_EXTENSION *ext) { + X509V3_EXT_METHOD *method = NULL; + void *ext_str = NULL; + unsigned char *p; + int len; + + if (ext == NULL) { + error("ssh_aia_get: ext is NULL"); + return(NULL); + } + + method = X509V3_EXT_get(ext); + if (method == NULL) { + debug("ssh_aia_get: cannot get method"); + return(NULL); + } + + p = ext->value->data; + len = ext->value->length; + if (method->it) { + ext_str = ASN1_item_d2i(NULL, &p, len, ASN1_ITEM_ptr(method->it)); + } else { + ext_str = method->d2i(NULL, &p, len); + } + if (ext_str == NULL) { + debug("ssh_aia_get: null ext_str!"); + return(NULL); + } + + return((AUTHORITY_INFO_ACCESS*)ext_str); +} + + +static void +ssh_aia_free(X509_EXTENSION *ext, AUTHORITY_INFO_ACCESS* aia) { + X509V3_EXT_METHOD *method = NULL; + + if (ext == NULL) { + error("ssh_aia_free: ext is NULL"); + return; + } + + method = X509V3_EXT_get(ext); + if (method == NULL) return; + + if (method->it) { + ASN1_item_free((void*)aia, ASN1_ITEM_ptr(method->it)); + } else { + method->ext_free(aia); + } +} + + +static int +ssh_aiaocsp_validate( + X509 *cert, + X509_STORE *x509store, + AUTHORITY_INFO_ACCESS *aia, + int *has_ocsp_url +) { + int ret = -1; + int k; + if (has_ocsp_url == NULL) { + fatal("ssh_aiaocsp_validate: has_ocsp_url is NULL"); + return(-1); /*;-)*/ + } + + *has_ocsp_url = 0; + for (k = 0; k < sk_ACCESS_DESCRIPTION_num(aia); k++) { + ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(aia, k); + GENERAL_NAME *gn; + ASN1_IA5STRING *uri; + ssh_ocsp_conn *conn; + + if (OBJ_obj2nid(ad->method) != NID_ad_OCSP) continue; + + gn = ad->location; +#if 0 +{ +BIO *bio = BIO_new_fp(stderr, BIO_NOCLOSE); +if (bio != NULL) { + BIO_puts(bio, "gn->type:"); + switch (gn->type) { + case GEN_OTHERNAME : BIO_puts(bio, "GEN_OTHERNAME"); break; + case GEN_EMAIL : BIO_puts(bio, "GEN_EMAIL" ); break; + case GEN_DNS : BIO_puts(bio, "GEN_DNS" ); break; + case GEN_X400 : BIO_puts(bio, "GEN_X400" ); break; + case GEN_DIRNAME : BIO_puts(bio, "GEN_DIRNAME" ); break; + case GEN_EDIPARTY : BIO_puts(bio, "GEN_EDIPARTY" ); break; + case GEN_URI : BIO_puts(bio, "GEN_URI" ); break; + case GEN_IPADD : BIO_puts(bio, "GEN_IPADD" ); break; + case GEN_RID : BIO_puts(bio, "GEN_RID" ); break; + default : BIO_puts(bio, "[unsupported]"); break; + } + BIO_puts(bio, "\n"); + BIO_free(bio); +} +} +#endif + if (gn->type != GEN_URI) continue; + + uri = gn->d.uniformResourceIdentifier; + *has_ocsp_url = 1; + + conn = ssh_ocsp_conn_new((const char*)uri->data); + if (conn == NULL) { + debug("ssh_aiaocsp_validate: cannot create ocsp connection"); + continue; + } + ret = ssh_ocsp_validate2(cert, x509store, conn); + ssh_ocsp_conn_free(&conn); + + if (ret >= 0) break; + } + + return(*has_ocsp_url ? ret : 1); +} + + +static int +ssh_ocsp_validate4cert(X509 *cert, X509_STORE *x509store) { + int found = 0; + int ret = -1; + int loc = -1; + + if (cert == NULL) return(0); + + for ( loc = X509_get_ext_by_NID(cert, NID_info_access, loc); + loc >= 0; + loc = X509_get_ext_by_NID(cert, NID_info_access, loc) + ) { + X509_EXTENSION *xe; + + xe = X509_get_ext(cert, loc); + if (xe == NULL) { + debug("ssh_ocsp_validate4cert: cannot get x509 extension"); + continue; + } + + {/*validate from AIA*/ + AUTHORITY_INFO_ACCESS *aia = ssh_aia_get(xe); + if (aia == NULL) continue; + + ret = ssh_aiaocsp_validate(cert, x509store, aia, &found); + + ssh_aia_free(xe, aia); + } + + if (ret >= 0) break; + } + + if (found) { + debug3("ssh_ocsp_validate4cert: validation result=%d", ret); + } else { + debug3("ssh_ocsp_validate4cert: no OCSP 'Service Locator' URL"); + } + return(found ? ret : 1); +} + + +int +ssh_ocsp_validate(X509 *cert, X509_STORE *x509store) { + int ret = -1; + ssh_ocsp_conn *conn = NULL; + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char buf[X509_NAME_MAXLEN]; + X509_NAME_oneline( X509_get_subject_name(cert), buf, sizeof(buf)); + debug3("ssh_ocsp_validate: for '%.*s'", (int) sizeof(buf), buf); + } + + switch (va.type) { + default: + /*when something is missing*/ + fatal("ssh_ocsp_validate: invalid validator type %d", va.type); + break; /*;-)*/ + case SSHVA_NONE: + ret = 1; + break; + case SSHVA_OCSP_CERT: + ret = ssh_ocsp_validate4cert(cert, x509store); + break; + case SSHVA_OCSP_SPEC: + conn = ssh_ocsp_conn_new(va.responder_url); + if (conn != NULL) { + ret = ssh_ocsp_validate2(cert, x509store, conn); + ssh_ocsp_conn_free(&conn); + } + break; + } + + return(ret); +} diff -ruN openssh-4.2p1/ssh-rand-helper.0 openssh-4.2p1+x509-5.5/ssh-rand-helper.0 --- openssh-4.2p1/ssh-rand-helper.0 2005-09-01 12:15:26.000000000 +0300 +++ openssh-4.2p1+x509-5.5/ssh-rand-helper.0 2006-04-26 00:05:20.000000000 +0300 @@ -1,4 +1,4 @@ -SSH-RAND-HELPER(8) OpenBSD System Manager's Manual SSH-RAND-HELPER(8) +SSH-RAND-HELPER(8) System Manager's Manual SSH-RAND-HELPER(8) NAME ssh-rand-helper - Random number gatherer for OpenSSH @@ -46,4 +46,4 @@ SEE ALSO ssh(1), ssh-add(1), ssh-keygen(1), sshd(8) -OpenBSD 3.8 April 14, 2002 1 +BSD April 14, 2002 BSD diff -ruN openssh-4.2p1/ssh-x509.c openssh-4.2p1+x509-5.5/ssh-x509.c --- openssh-4.2p1/ssh-x509.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-x509.c 2006-03-10 23:35:23.000000000 +0200 @@ -0,0 +1,832 @@ +/* + * 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 + * 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 "ssh-x509.h" +#include "ssh-xkalg.h" +#include "log.h" +#include +#include "xmalloc.h" +#include "uuencode.h" +#include +#include "bufaux.h" +#include "x509store.h" +#include "compat.h" + + +int (*pssh_x509cert_check)(X509 *_cert) = NULL; + + +static char* +openssl_errormsg(char *buf, size_t len) { + ERR_error_string_n(ERR_get_error(), buf, len); + + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + return(buf); +} + + +#ifndef SSH_X509STORE_DISABLED +static const char* +x509key_find_subject(const char* s) { + static const char *keywords[] = { + "subject", + "distinguished name", + "distinguished-name", + "distinguished_name", + "distinguishedname", + "dn", + NULL + }; + const char **q, *p; + size_t len; + + 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; + + for (p = s + len; *p && isspace((int)*p); p++) + {/*skip space*/} + if (!*p) { + error("x509key_find_subject: no data after keyword"); + return(NULL); + } + if (*p == ':' || *p == '=') { + for (p++; *p && isspace((int)*p); p++) + {/*skip space*/} + if (!*p) { + error("x509key_find_subject: no data after separator"); + return(NULL); + } + } + if (*p == '/' || *p == ',') { + /*skip leading [Relative]DistinguishedName elements separator*/ + for (p++; *p && isspace((int)*p); p++) + {/*skip space*/} + if (!*p) { + error("x509key_find_subject: no data"); + return(NULL); + } + } + return(p); + } + return(NULL); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifndef SSH_X509STORE_DISABLED +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; + int has_more = 0; + + str = xmalloc(strlen(_str) + 1); /*fatal on error*/ + strcpy(str, _str); + + p = (char*)str; + while (*p) { + int nid; + for (; *p && isspace((int)*p); p++) + {/*skip space*/} + if (!*p) break; + + /* get shortest token */ + { + char *tokenA = strchr(p, ','); + char *tokenB = strchr(p, '/'); + + if (tokenA == NULL) { + token = tokenB; + } else if (tokenB == NULL) { + token = tokenA; + } else { + token = (tokenA < tokenB) ? tokenA : tokenB; + } + } + if (token) { + has_more = 1; + *token = 0; + } else { + has_more = 0; + token = p + strlen(p); + } + q = strchr(p, '='); + if (!q) { + error("x509key_str2X509NAME: cannot parse '%.200s' ...", p); + ret = 0; + break; + } + *q = 0; + nid = OBJ_txt2nid(p); +#ifdef SSH_OPENSSL_DN_WITHOUT_EMAIL + if (nid == NID_undef) { + /* work around for OpenSSL 0.9.7+ */ + if (strcasecmp(p, "Email") == 0) { + nid = OBJ_txt2nid("emailAddress"); + } + } +#endif /* def SSH_OPENSSL_DN_WITHOUT_EMAIL */ + if (nid == NID_undef) { + error("x509key_str2X509NAME: cannot get nid from string '%.200s'", p); + ret = 0; + break; + } + + 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 (has_more) p++; + } + + if (str) xfree(str); + debug3("x509key_str2X509NAME: return %d", ret); + return(ret); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifndef SSH_X509STORE_DISABLED +Key* +x509key_from_subject(int _keytype, const char* _cp) { + int ret = 1; + Key* key = NULL; + X509_NAME *subj; + const char *subject; + + 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=[%.*s]", X509_NAME_MAXLEN, subject); + key = key_new(_keytype); + if (key == NULL) { + error("x509key_from_subject: out of memory"); + return(NULL); + } + + if (ret > 0) { + subj = X509_get_subject_name(key->x509); + if (subj == NULL) { + error("x509key_from_subject: new x509 key without subject"); + ret = 0; + } + } + + if (ret > 0) { + ret = x509key_str2X509NAME(subject, subj); + } + + if (ret <= 0) { + if (key != NULL) { + key_free(key); + key = NULL; + } + } + debug3("x509key_from_subject: return %p", (void*)key); + return(key); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +static Key* +x509_to_key(X509 *x509) { + Key *key = NULL; + EVP_PKEY *env_pkey; + + env_pkey = X509_get_pubkey(x509); + if (env_pkey == NULL) { + char ebuf[256]; + error("x509_to_key: X509_get_pubkey fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); + return(NULL); + } + /*else*/ + debug3("x509_to_key: X509_get_pubkey done!"); + + switch (env_pkey->type) { + case EVP_PKEY_RSA: + key = key_new(KEY_UNSPEC); + key->x509 = x509; + key->rsa = EVP_PKEY_get1_RSA(env_pkey); + key->type = KEY_X509_RSA; +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + + case EVP_PKEY_DSA: + key = key_new(KEY_UNSPEC); + key->x509 = x509; + key->dsa = EVP_PKEY_get1_DSA(env_pkey); + key->type = KEY_X509_DSA; +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + + default: + fatal("ssh_x509_key_size: unknow env_pkey->type %d", env_pkey->type); + /*unreachable code*/ + } + + return(key); +} + + +Key* +x509key_from_blob(const u_char *blob, int blen) { + Key* key = NULL; + BIO *mbio; + + /* convert blob data to BIO certificate data */ + mbio = BIO_new(BIO_s_mem()); + if (mbio == NULL) return(NULL); + BIO_write(mbio, blob, blen); + BIO_flush(mbio); + + debug3("x509key_from_blob: We have %d bytes available in BIO", BIO_pending(mbio)); + + { /* read X509 certificate from BIO data */ + X509* x509 = NULL; + x509 = d2i_X509_bio(mbio, NULL); + if (x509 == NULL) { + /* We will print only debug info !!! + * This method is used in place where we can only check incomming data. + * 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 %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); + } else { + key = x509_to_key(x509); + if (key == NULL) + X509_free(x509); + } + } + + /* This call will walk the chain freeing all the BIOs */ + BIO_free_all(mbio); + return(key); +} + + +static int +x509key_check(const char* method, const Key *key) { + if (key == NULL) + { error("%.50s: no key", method); return(0); } + + if (key->type != KEY_X509_RSA && + key->type != KEY_X509_DSA ) + { error("%.50s: cannot handle key type %d", method, key->type); return(0); } + + if (key->x509 == NULL) + { error("%.50s: no X509 key", method); return(0); } + + return(1); +} + + +int +x509key_to_blob(const Key *key, Buffer *b) { + int len; + void *str; + u_char *p; + + if (!x509key_check("x509key_to_blob", key)) return(0); + + len = i2d_X509(key->x509, NULL); + str = xmalloc(len); /*fatal on error*/ + p = str; + i2d_X509(key->x509, &p); + buffer_append(b, str, len); + xfree(str); + return(1); +} + + +char* +x509key_subject(const Key *key) { + char *buf = NULL; + + if (!x509key_check("x509key_subject", key)) return(buf); + + buf = xmalloc(X509_NAME_MAXLEN); /*fatal on error*/ + X509_NAME_oneline(X509_get_subject_name(key->x509), buf, X509_NAME_MAXLEN); + return(buf); +} + + +int +x509key_write(const Key *key, FILE *f) { + int ret = 0; + Buffer b; + size_t n; + + if (!x509key_check("x509key_write_blob", key)) return(ret); + + buffer_init(&b); + ret = x509key_to_blob(key, &b); + if (ret) { + /* write ssh key name */ + const char *ktype = key_ssh_name(key); + n = strlen(ktype); + ret = ( fwrite(ktype, 1, n, f) == n ) && + ( fwrite(" ", 1, 1, f) == 1 ); + } + if (ret) { + char uu[1<<12]; /* 4096 bytes */ + + n = uuencode(buffer_ptr(&b), buffer_len(&b), uu, sizeof(uu)); + ret = n > 0; + if (ret) { + ret = (fwrite(uu, 1, n, f) == n); + } + } + buffer_free(&b); + return(ret); +} + + +#ifndef SSH_X509STORE_DISABLED +int +x509key_write_subject(const Key *key, FILE *f) { + return(x509key_write_subject2(key, key_ssh_name(key), f)); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifndef SSH_X509STORE_DISABLED +int +x509key_write_subject2(const Key *key, const char *keyname, FILE *f) { + BIO *out; + char buf[X509_NAME_MAXLEN]; + + if (!x509key_check("x509key_write_subject2", key)) return(0); + if (keyname == NULL) return(0); + + out = BIO_new_fp(f, BIO_NOCLOSE); + if (out == NULL) return(0); +#ifdef VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + out = BIO_push(tmpbio, out); + } +#endif + + BIO_puts(out, keyname); + BIO_puts(out, " Subject:"); + X509_NAME_oneline(X509_get_subject_name(key->x509), buf, sizeof(buf)); + BIO_puts(out, buf); + + BIO_free_all(out); + return(1); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +Key* +x509key_load_cert(Key *key, FILE *fp) { + if (key == NULL) return(NULL); + + if ( (key->type == KEY_RSA) || + (key->type == KEY_DSA) ) { + key->x509 = PEM_read_X509(fp, NULL, NULL, NULL); + if (key->x509 == NULL) { + char ebuf[256]; + 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; + debug("read X509 certificate done: type %.40s", key_type(key)); + } + } + return(key); +} + + +static int +x509key_save_cert(FILE *fp, X509 *x509) { + int ret = 0; + BIO *out; + char buf[X509_NAME_MAXLEN]; + + out = BIO_new_fp(fp, BIO_NOCLOSE); + if (out == NULL) return(0); +#ifdef VMS + { + BIO *tmpbio = BIO_new(BIO_f_linebuffer()); + out = BIO_push(tmpbio, out); + } +#endif + + BIO_puts(out, "issuer= "); + X509_NAME_oneline(X509_get_issuer_name(x509), buf, sizeof(buf)); + BIO_puts(out, buf); + BIO_puts(out, "\n"); + + BIO_puts(out, "subject= "); + X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); + BIO_puts(out, buf); + BIO_puts(out, "\n"); + { + const char *alstr = (const char*)X509_alias_get0(x509, NULL); + if (alstr == NULL) alstr = ""; + BIO_puts(out, alstr); + BIO_puts(out, "\n"); + } + ret = PEM_write_bio_X509(out, x509); + if (!ret) { + char ebuf[256]; + error("x509key_save_cert: PEM_write_bio_X509 fail %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); + } + + BIO_free_all(out); + return(ret); +} + + +int +x509key_save_pem( + FILE *fp, + const Key *key, + const EVP_CIPHER *cipher, + u_char *passphrase, + int len +) { + if (!x509key_check("x509key_save_pem", key)) return(0); + + switch (key->type) { + case KEY_X509_DSA: + if (PEM_write_DSAPrivateKey(fp, key->dsa, cipher, passphrase, len, NULL, NULL)) + return(x509key_save_cert(fp, key->x509)); + break; + case KEY_X509_RSA: + if (PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL)) + return(x509key_save_cert(fp, key->x509)); + break; + } + return(0); +} + + +#ifndef SSH_X509STORE_DISABLED +/* + * We can check only by Subject (Distinguished Name): + * - sshd receive from client only x509 certificate !!! + * - sshadd -d ... send only x509 certificate !!! + * - otherwise Key might contain private key + */ +int +ssh_x509_equal(const Key *a, const Key *b) { + if (!x509key_check("ssh_x509_equal", a)) return(1); + if (!x509key_check("ssh_x509_equal", b)) return(-1); + +#if 1 +/* + * We must use own method to compare two X509_NAMEs instead of OpenSSL + * function[s]! See notes before body of "ssh_X509_NAME_cmp()". + */ + { + X509_NAME *nameA = X509_get_subject_name(a->x509); + X509_NAME *nameB = X509_get_subject_name(b->x509); + return(ssh_X509_NAME_cmp(nameA, nameB)); + } +#else + return(X509_subject_name_cmp(a->x509, b->x509)); +#endif +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +int +ssh_x509key_type(const char *name) { + SSHX509KeyAlgs *p; + int k; + + if (name == NULL) { + fatal("ssh_x509key_type: name is NULL"); + return(KEY_UNSPEC); /*unreachable code*/ + } + + k = ssh_xkalg_nameind(name, &p, -1); + return((k >= 0) ? p->type : KEY_UNSPEC); +} + + +static SSHX509KeyAlgs* +ssh_first_xkalg(int type) { + SSHX509KeyAlgs *p; + int k; + + k = ssh_xkalg_typeind(type, &p, -1); + return((k >= 0) ? p : NULL); +} + + +const char* +ssh_x509key_name(const Key *k) { + int type; + SSHX509KeyAlgs *p; + + if (k == NULL) { + fatal("ssh_x509key_name: key is NULL"); + return(NULL); /*unreachable code*/ + } + + type = k->type; + if ((type != KEY_X509_RSA) && (type != KEY_X509_DSA)) return(NULL); + + p = ssh_first_xkalg(type); + if (p != NULL) return(p->name); + + error("ssh_x509key_name: cannot handle type %d", type); + return(NULL); +} + + +int +ssh_x509_sign( + const Key *key, + u_char **psignature, u_int *psignaturelen, + const u_char *data, u_int datalen +) { + int ret = -1; + SSHX509KeyAlgs *xkalg; + u_char sigret[256]; + u_int siglen; + + if (!x509key_check("ssh_x509_sign", key)) return(ret); + if ((key->rsa == NULL) && (key->dsa == NULL)) { + error("ssh_x509_sign: missing private key"); + return(ret); + } + + debug3("ssh_x509_sign: key_type=%.20s, key_ssh_name=%.40s", key_type(key), key_ssh_name(key)); + ret = 1; + { + EVP_PKEY *privkey = EVP_PKEY_new(); + if (privkey == NULL) { + error("ssh_x509_sign: out of memory"); + ret = -1; + } + else { + ret = (key->rsa) + ? EVP_PKEY_set1_RSA(privkey, key->rsa) + : EVP_PKEY_set1_DSA(privkey, key->dsa); + + if (ret <= 0) { + char ebuf[256]; + error("ssh_x509_sign: EVP_PKEY_set1_XXX: failed %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); + } + } + + if (ret > 0) { + xkalg = ssh_first_xkalg(key->type); + if (xkalg == NULL) { + error("ssh_x509_sign: cannot handle type %d", key->type); + ret = -1; + } + } + if (ret > 0) { + EVP_MD_CTX ctx; + + debug3("ssh_x509_sign: alg=%.50s, md=%.30s", xkalg->name, xkalg->dgst.name); + EVP_SignInit(&ctx, xkalg->dgst.evp); + EVP_SignUpdate(&ctx, data, datalen); + ret = EVP_SignFinal(&ctx, sigret, &siglen, privkey); + if (ret <= 0) { + char ebuf[256]; + error("ssh_x509_sign: digest failed: %.*s", + sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); + } + } + EVP_PKEY_free(privkey); + } + if (ret > 0) { + Buffer b; + const char *signame; + + buffer_init(&b); + signame = X509PUBALG_SIGNAME(xkalg); + debug3("ssh_x509_sign: signame=%.50s", signame); + buffer_put_cstring(&b, signame); + buffer_put_string(&b, sigret, siglen); + + { + u_int len = buffer_len(&b); + if (psignaturelen != NULL) + *psignaturelen = len; + + if (psignature != NULL) { + *psignature = xmalloc(len); /*fatal on error*/ + memcpy(*psignature, buffer_ptr(&b), len); + } + } + buffer_free(&b); + } + ret = ret > 0 ? 0 : -1; + debug3("ssh_x509_sign: return %d", ret); + return(ret); +} + + +int +ssh_x509_verify( + const Key *key, + const u_char *signature, u_int signaturelen, + const u_char *data, u_int datalen +) { + int ret = -1; + u_char *sigblob = NULL; + uint len = 0; + + if (!x509key_check("ssh_x509_verify", key)) return(ret); + + { /* get signature data only */ + Buffer b; + + ret = 1; + buffer_init(&b); + buffer_append(&b, signature, signaturelen); + + { /* check signature format */ + char *sigformat = buffer_get_string(&b, NULL); + + debug3("ssh_x509_verify: signature format = %.40s", sigformat); + if (!ssh_is_x509signame(sigformat)) { + error("ssh_x509_verify: cannot handle signature format %.40s", sigformat); + ret = 0; + } + xfree(sigformat); + } + + if (ret > 0) { + int rlen; + + sigblob = buffer_get_string(&b, &len); + rlen = buffer_len(&b); + if (rlen != 0) { + error("ssh_x509_verify: remaining bytes in signature %d", rlen); + ret = -1; + } + } + buffer_free(&b); + } + + if (ret > 0 ) { + EVP_PKEY* pubkey = X509_get_pubkey(key->x509); + SSHX509KeyAlgs *xkalg; + int loc; + + if (pubkey == NULL) { + error("ssh_x509_verify: no 'X509 Public Key'"); + ret = -1; + } + if (ret > 0) { + loc = ssh_xkalg_typeind(key->type, &xkalg, -1); + if (loc < 0) { + error("ssh_x509_verify: cannot handle type %d", key->type); + ret = -1; + } + } + if (ret > 0) { + for (; loc >= 0; loc = ssh_xkalg_typeind(key->type, &xkalg, loc)) { + EVP_MD_CTX ctx; + + debug3("ssh_x509_verify: md=%.30s, loc=%d", xkalg->dgst.name, loc); + EVP_VerifyInit(&ctx, xkalg->dgst.evp); + EVP_VerifyUpdate(&ctx, data, datalen); + ret = EVP_VerifyFinal(&ctx, sigblob, len, pubkey); + if (ret > 0) break; + } + if (ret <= 0) { + debug3("ssh_x509_verify: failed for all digests"); + ret = 0; + } + } + EVP_PKEY_free(pubkey); + } + if (sigblob) { + memset(sigblob, 's', len); + xfree(sigblob); + sigblob = NULL; + } + if (ret > 0) { + if (pssh_x509cert_check != NULL) { + ret = pssh_x509cert_check(key->x509); + } else { + error("ssh_x509_verify: pssh_x509cert_check is NULL"); + ret = -1; + } + } + ret = ret > 0 ? 1 : (ret < 0 ? -1 : 0); + debug3("ssh_x509_verify: return %d", ret); + return(ret); +} + + +u_int +ssh_x509_key_size(const Key *key) { + EVP_PKEY *pkey; + int k = 0; + + if (!x509key_check("key_size", key)) goto done; + + pkey = X509_get_pubkey(key->x509); + if (pkey == NULL) goto done; + + switch(pkey->type) { + case EVP_PKEY_RSA: + /* BN_num_bits return int (!): XXX */ + k = BN_num_bits(pkey->pkey.rsa->n); + break; + case EVP_PKEY_DSA: + /*OpenSSH like this*/ + k = BN_num_bits(pkey->pkey.dsa->p); + break; + default: + fatal("ssh_x509_key_size: unknow pkey->type %d", pkey->type); + /*unreachable code*/ + } + EVP_PKEY_free(pkey); +done: + return((u_int) k); +} diff -ruN openssh-4.2p1/ssh-x509.h openssh-4.2p1+x509-5.5/ssh-x509.h --- openssh-4.2p1/ssh-x509.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-x509.h 2005-08-13 17:58:58.000000000 +0300 @@ -0,0 +1,73 @@ +#ifndef SSH_X509_H +#define SSH_X509_H +/* + * 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 + * 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" +#include "key.h" +#include "buffer.h" + + +#ifndef SSH_X509STORE_DISABLED +/* + * Method return a key(x509) only with "Subject"("Distinguished Name") ! + */ +Key* x509key_from_subject(int _keytype, const char* _cp); +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +Key* x509key_from_blob(const u_char *blob, int blen); +int x509key_to_blob(const Key *key, Buffer *b); + +char* x509key_subject(const Key *key); + +/* + * Method write x509 certificate as blob. + */ +int x509key_write(const Key *key, FILE *f); +#ifndef SSH_X509STORE_DISABLED +/* + * Method write x509 certificate subject. + */ +int x509key_write_subject(const Key *key, FILE *f); +int x509key_write_subject2(const Key *key, const char *keyname, FILE *f); +#endif /*ndef SSH_X509STORE_DISABLED*/ + +Key* x509key_load_cert(Key *key, FILE *fp); + +int x509key_save_pem(FILE *fp, const Key *key, const EVP_CIPHER *cipher, u_char *passphrase, int len); + +#ifndef SSH_X509STORE_DISABLED +int ssh_x509_equal(const Key *a, const Key *b); +#endif /*ndef SSH_X509STORE_DISABLED*/ + +int ssh_x509key_type(const char *name); +const char* ssh_x509key_name(const Key *k); + +int ssh_x509_sign(const Key *key, u_char **psignature, u_int *psignaturelen, const u_char *data, u_int datalen); +int ssh_x509_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen); +u_int ssh_x509_key_size(const Key *key); + + +#endif /* SSH_X509_H */ diff -ruN openssh-4.2p1/ssh-xkalg.c openssh-4.2p1+x509-5.5/ssh-xkalg.c --- openssh-4.2p1/ssh-xkalg.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-xkalg.c 2006-05-12 00:36:42.000000000 +0300 @@ -0,0 +1,464 @@ +/* + * 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: + * 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 "ssh-xkalg.h" +#include "log.h" +#include "key.h" +#include "xmalloc.h" + + +#define SHARAW_DIGEST_LENGTH (2*SHA_DIGEST_LENGTH) + + +#ifdef OPENSSL_NO_DSA +# error "OPENSSL_NO_DSA" +#endif +#ifdef OPENSSL_NO_SHA +# error "OPENSSL_NO_SHA" +#endif + + +#define EVP_PKEY_DSARAW_method \ + DSARAW_sign,DSARAW_verify, \ + {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3,EVP_PKEY_DSA4,0} + + +static int/*bool*/ +DSARAW_sign( + int type, + const unsigned char *dgst, + int dlen, + unsigned char *sigret, unsigned int *siglen, + DSA *dsa +) { + int ret = 0; + DSA_SIG *sig = NULL; + +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG DSARAW_sign:\n"); +#endif + sig = DSA_do_sign(dgst, dlen, dsa); + if (sig == NULL) { + *siglen=0; + return(ret); + } + + *siglen = SHARAW_DIGEST_LENGTH; + if (sigret != NULL) { + u_int rlen, slen; + rlen = BN_num_bytes(sig->r); + slen = BN_num_bytes(sig->s); + if (rlen > SHA_DIGEST_LENGTH || slen > SHA_DIGEST_LENGTH) { + error("DSARAW_sign: bad sig size %u %u", rlen, slen); + goto done; + } + memset(sigret, 0, SHARAW_DIGEST_LENGTH); + BN_bn2bin(sig->r, sigret + SHARAW_DIGEST_LENGTH - SHA_DIGEST_LENGTH - rlen); + BN_bn2bin(sig->s, sigret + SHARAW_DIGEST_LENGTH - slen); + } + ret = 1; + +done: + DSA_SIG_free(sig); + return(ret); +} + + +static int +DSARAW_verify( + int type, + const unsigned char *dgst, int dgst_len, + const unsigned char *sigbuf, int siglen, + DSA *dsa +) { + int ret = -1; + DSA_SIG *sig = NULL; + +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG DSARAW_verify: siglen=%d\n", siglen); +#endif + if (siglen != SHARAW_DIGEST_LENGTH) return(ret); + + sig = DSA_SIG_new(); + if (sig == NULL) return(ret); + + sig->r = BN_new(); + if (sig->r == NULL) + fatal("DSARAW_verify: BN_new failed"); + sig->s = BN_new(); + if (sig->s == NULL) + fatal("DSARAW_verify: BN_new failed"); + + BN_bin2bn(sigbuf , SHA_DIGEST_LENGTH, sig->r); + BN_bin2bn(sigbuf+SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH, sig->s); + + ret = DSA_do_verify(dgst, dgst_len, sig, dsa); + + DSA_SIG_free(sig); + return(ret); +} + + +static int +init(EVP_MD_CTX *ctx) { + return(SHA1_Init(ctx->md_data)); +} + + +static int +update(EVP_MD_CTX *ctx, const void *data, unsigned long count) { + return(SHA1_Update(ctx->md_data, data, count)); +} + + +static int +final(EVP_MD_CTX *ctx, unsigned char *md) { + return(SHA1_Final(md, ctx->md_data)); +} + + +#ifndef EVP_MD_FLAG_FIPS +# define EVP_MD_FLAG_FIPS 0 +#endif + +static const +EVP_MD dss1_md = { + NID_dsa, + NID_dsaWithSHA1, + SHA_DIGEST_LENGTH, + EVP_MD_FLAG_FIPS, + init, + update, + final, + NULL, + NULL, + EVP_PKEY_DSARAW_method, + SHA_CBLOCK, + sizeof(EVP_MD *)+sizeof(SHA_CTX), +}; + + +extern const EVP_MD* +EVP_dss1raw(void); + + +const EVP_MD* +EVP_dss1raw(void) { + return(&dss1_md); +} + + +/* SSH X509 public key algorithms*/ +static int x509keyalgs_initialized = 0; +static SSHX509KeyAlgs x509keyalgs[10]; + + +static void +initialize_xkalg(void) { + SSHX509KeyAlgs *p = x509keyalgs; + int k; + + if (x509keyalgs_initialized) return; + +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG initialize_xkalg:\n"); +#endif + k = sizeof(x509keyalgs) / sizeof(x509keyalgs[0]); + for (; k > 0; k--, p++) { + p->type = KEY_UNSPEC; + p->name = NULL; + p->dgst.name = NULL; + p->dgst.evp = NULL; + p->signame = NULL; + } + x509keyalgs_initialized = 1; +} + + +static void +add_default_xkalg(void) { +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG add_default_xkalg:\n"); +#endif + + /*RSA public key algorithm*/ + /* OpenSSH defaults note that + * draft-ietf-secsh-transport-NN.txt where NN <= 12 + * don't define signature format + */ + if (ssh_add_x509key_alg("x509v3-sign-rsa,rsa-md5") < 0) + fatal("ssh_init_xkalg: oops"); + if (ssh_add_x509key_alg("x509v3-sign-rsa,rsa-sha1") < 0) + fatal("ssh_init_xkalg: oops"); + +#if 0 + /* "draft-ietf-secsh-x509-NN.txt" where NN <= 03 */ +/* NOT YET FULLY IMPLEMENTED */ + if (ssh_add_x509key_alg("x509v3-sign-rsa-sha1,rsa-sha1,ssh-rsa") < 0) + fatal("ssh_init_xkalg: oops"); +#endif + + /*DSA public key algorithm*/ + /* OpenSSH default compatible with + * draft-ietf-secsh-transport-NN.txt where NN <= 12 + */ + if (ssh_add_x509key_alg("x509v3-sign-dss,dss-asn1") < 0) + fatal("ssh_init_xkalg: oops"); + /* some non OpenSSH implementations incompatible with + * draft-ietf-secsh-transport-NN.txt where NN <= 12 + */ + if (ssh_add_x509key_alg("x509v3-sign-dss,dss-raw") < 0) + fatal("ssh_init_xkalg: oops"); + +#if 0 + /* draft-ietf-secsh-x509-NN.txt where NN <= 03 */ +/* NOT YET FULLY IMPLEMENTED */ + if (ssh_add_x509key_alg("x509v3-sign-dss-sha1,dss-raw,ssh-dss") < 0) + fatal("ssh_init_xkalg: oops"); +#endif +} + + +void +fill_default_xkalg(void) { + SSHX509KeyAlgs *p = x509keyalgs; + +#ifdef TRACE_XKALG +fprintf(stderr, "TRACE_XKALG fill_default_xkalg:\n"); +#endif + initialize_xkalg(); + if (p[0].name == NULL) add_default_xkalg(); +} + + +static const EVP_MD* +ssh_evp_md(const char *dgstname) { + if (dgstname == NULL) { + fatal("ssh_get_md: dgstname is NULL"); + return(NULL); /*unreachable code*/ + } + + if (strcasecmp("rsa-sha1", dgstname) == 0) return(EVP_sha1()); + if (strcasecmp("rsa-md5" , dgstname) == 0) return(EVP_md5()); +/*?: if (strcasecmp("ssh-rsa" , dgstname) == 0) return(EVP_sha1());*/ + + if (strcasecmp("dss-asn1", dgstname) == 0) return(EVP_dss1()); + if (strcasecmp("dss-raw" , dgstname) == 0) return(EVP_dss1raw()); +/*?: if (strcasecmp("ssh-dss" , dgstname) == 0) return(EVP_dss1raw());*/ + +#if 0 + fatal("ssh_get_md: invalid sigformat '%.10s'", dgstname); +#endif + return(NULL); /*unreachable code*/ +} + + +int +ssh_add_x509key_alg(const char *data) { + char *name, *mdname, *signame; + SSHX509KeyAlgs* p; + const EVP_MD* md; + + if (data == NULL) { + error("ssh_add_x509pubkey_alg: data is NULL"); + return(-1); + } + + name = xstrdup(data); /*fatal on error*/ + + mdname = strchr(name, ','); + if (mdname == NULL) { + error("ssh_add_x509pubkey_alg: cannot get digest"); + goto err; + } + *mdname++ = '\0'; + + signame = strchr(mdname, ','); + if (signame != NULL) *signame++ = '\0'; + + md = ssh_evp_md(mdname); + if (md == NULL) { + error("ssh_add_x509pubkey_alg: unsupported digest"); + goto err; + } + + initialize_xkalg(); + p = x509keyalgs; + { + int k = sizeof(x509keyalgs) / sizeof(x509keyalgs[0]); + + for (; k > 0; k--, p++) { + if (p->name == NULL) break; + } + if (k <= 0) { + error("ssh_add_x509pubkey_alg: insufficient slots"); + goto err; + } + } + + if ((md == EVP_dss1()) || (md == EVP_dss1raw())) { + p->type = KEY_X509_DSA; + } else { + p->type = KEY_X509_RSA; + } + p->name = name; + p->dgst.name = mdname; + p->dgst.evp = md; + p->signame = signame; + + return (1); + +err: + xfree((void*)name); + return (-1); +} + + +int/*bool*/ +ssh_is_x509signame(const char *signame) { + SSHX509KeyAlgs *xkalg; + int k; + + if (signame == NULL) { + fatal("ssh_is_x509signame: signame is NULL"); + return(0); /*unreachable code*/ + } + + initialize_xkalg(); + xkalg = x509keyalgs; + k = sizeof(x509keyalgs) / sizeof(x509keyalgs[0]); + + for (; k > 0; k--, xkalg++) { + if (xkalg->name == NULL) return(0); + if (strcmp(signame, X509PUBALG_SIGNAME(xkalg)) == 0) return(1); + } + return(0); +} + + +int +ssh_xkalg_nameind(const char *name, SSHX509KeyAlgs **q, int loc) { + int k, n; + SSHX509KeyAlgs *p; + + if (name == NULL) return (-1); + + initialize_xkalg(); + k = (loc < 0) ? 0 : (loc + 1); + n = sizeof(x509keyalgs) / sizeof(x509keyalgs[0]); + if (k < n) p = &x509keyalgs[k]; + + for (; k < n; k++, p++) { + if (p->name == NULL) return(-1); + if (strcmp(p->name, name) == 0) { + if (q) *q = p; + return(k); + } + } + return(-1); +} + + +int +ssh_xkalg_typeind(int type, SSHX509KeyAlgs **q, int loc) { + int k, n; + SSHX509KeyAlgs *p; + + initialize_xkalg(); + k = (loc < 0) ? 0 : (loc + 1); + n = sizeof(x509keyalgs) / sizeof(x509keyalgs[0]); + if (k < n) p = &x509keyalgs[k]; + + for (; k < n; k++, p++) { + if (p->name == NULL) return(-1); + if (p->type == type) { + if (q) *q = p; + return(k); + } + } + return(-1); +} + + +void +ssh_list_xkalg(int type, Buffer *b) { + SSHX509KeyAlgs *xkalg; + int loc; + + if ((type != KEY_X509_RSA) && (type != KEY_X509_DSA)) { + error("ssh_list_xkalg: %d is not x509 key", type); + return; + } + if (b == NULL) { + error("ssh_list_xkalg: buffer is NULL"); + return; + } + +#if 1 + /* add only(!) first found */ + loc = ssh_xkalg_typeind(type, &xkalg, -1); + if (loc < 0) return; + + if (buffer_len(b) > 0) buffer_append(b, ",", 1); + buffer_append(b, xkalg->name, strlen(xkalg->name)); +#else +IMPORTANT NOTE: + For every unique "key name" we MUST define unique "key type" +otherwise cannot distinguish them ! +As example structure Kex contain integer attribute "kex_type" +and kex use method "load_host_key" to find hostkey. When client +request hostkey algorithms (comma separated list with names) +server should be able to find first hostkey that match one of them. +Note to "load_host_key" is assigned method "get_hostkey_by_type" +defined in "sshd.c". + + for ( + loc = ssh_xkalg_typeind(type, &xkalg, -1); + loc >= 0; + loc = ssh_xkalg_typeind(type, &xkalg, loc) + ) { + const char *p; + int dupl, k; + + p = xkalg->name; + + dupl = 0; + + for ( + k = ssh_xkalg_typeind(type, &xkalg, -1); + (k >= 0) && (k < loc); + k = ssh_xkalg_typeind(type, &xkalg, k) + ) { + if (strcmp(p, xkalg->name) == 0) { + dupl = 1; + break; + } + } + if (dupl) continue; + + if (buffer_len(b) > 0) buffer_append(b, ",", 1); + buffer_append(b, p, strlen(p)); + } +#endif +} diff -ruN openssh-4.2p1/ssh-xkalg.h openssh-4.2p1+x509-5.5/ssh-xkalg.h --- openssh-4.2p1/ssh-xkalg.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/ssh-xkalg.h 2005-08-13 14:01:31.000000000 +0300 @@ -0,0 +1,58 @@ +#ifndef SSH_XKALG_H +#define SSH_XKALG_H +/* + * 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: + * 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" +#include +#include "buffer.h" + + +typedef struct { + int type; + const char *name; + struct { + const char *name; + const EVP_MD *evp; + } dgst; + const char *signame; +} SSHX509KeyAlgs; +#define X509PUBALG_SIGNAME(p) (p->signame ? p->signame : p->name) + + +void fill_default_xkalg(void); + /* format "name,dgst_name[,sig_name]" */ +int ssh_add_x509key_alg(const char *data); + + +int/*bool*/ ssh_is_x509signame(const char *signame); + +int ssh_xkalg_nameind(const char *name, SSHX509KeyAlgs **q, int loc); +int ssh_xkalg_typeind(int type, SSHX509KeyAlgs **q, int loc); + +void ssh_list_xkalg(int type, Buffer *b); + + +#endif /* SSH_XKALG_H */ diff -ruN openssh-4.2p1/tests/CA/1-cre_cadb.sh openssh-4.2p1+x509-5.5/tests/CA/1-cre_cadb.sh --- openssh-4.2p1/tests/CA/1-cre_cadb.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/1-cre_cadb.sh 2006-03-12 22:39:08.000000000 +0200 @@ -0,0 +1,335 @@ +#! /bin/sh +# Copyright (c) 2002-2006 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Create a new certificate authority config and database. +# + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/1-cre_cadb.sh$//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" + + +# === +# args: +# $1 - type +echo_CA_common_options () { +cat < "$1" +[ ca ] +default_ca = CA_OpenSSH_rsa_md5 + + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + + +[ req ] +default_bits = 1024 +distinguished_name = req_distinguished_name +attributes = req_attributes +#prompt = no + +# The extensions to add to a certificate request: +#???req_extensions = usr_cert + + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = $SSH_DN_C +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = $SSH_DN_ST + +localityName = Locality Name (eg, city) +localityName_default = $SSH_DN_L + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = $SSH_DN_O + +0.organizationalUnitName = Organizational Unit1 Name (eg, section1 - optional) +0.organizationalUnitName_default = ${SSH_DN_OU}-1 + +1.organizationalUnitName = Organizational Unit2 Name (eg, section2 - optional) +1.organizationalUnitName_default = ${SSH_DN_OU}-2 + +2.organizationalUnitName = Organizational Unit3 Name (eg, section3 - optional) +2.organizationalUnitName_default = ${SSH_DN_OU}-3 + +commonName = Common Name (eg, YOUR name) +commonName_min = 2 +commonName_max = 64 + +emailAddress = Email Address (optional) +emailAddress_max = 40 +emailAddress_default = $SSH_DN_EM + + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + + +[ ca_cert ] +# PKIX recommendation. + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +# Since we generate OpenSSH test CA we comment next line. +#basicConstraints=CA:true + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated OpenSSH Test CA Certificate" + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# Since we verify CRL signatures cRLSign must present +keyUsage = keyCertSign, cRLSign + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always + +# To test CRL presence this extension should exist +crlDistributionPoints = URI:attribute_only_exist +EOF + + +# X.509 extensions: SSH client certificates +cat << EOF >> "$1" + + +[ usr_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints = CA:FALSE +nsCertType = client, email + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated OpenSSH Test Client Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +EOF + +echo_CA_ocsp_options >> "$1" + + +# X.509 extensions: SSH server certificates +cat << EOF >> "$1" + + +[ srv_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints = CA:FALSE + +# To test OpenSSH hostbased authentication we need +# following certificate purposes: +nsCertType = server,client +# Normal for server certificate is: +#nsCertType = server +# but in last case me must disable check of certificate purposes +# in sshd_config otherwise hostbased fail. + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated OpenSSH Test Server Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always + +# Some SSH clients require server certificate to contain +# correct alternate name of type DNS (FQDN) +subjectAltName = DNS:localhost +EOF + +echo_CA_ocsp_options >> "$1" + + +# X.509 extensions: OCSP Validator certificates +if test "x$SSH_OCSP" = "xyes"; then +cat << EOF >> "$1" + + +[ ocsp_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints = CA:FALSE + +# Normal for validator certificate is: +nsCertType = objsign + +# This is typical in keyUsage for a validator certificate. +keyUsage = nonRepudiation, digitalSignature + +# This should present for a validator certificate. +extendedKeyUsage = OCSPSigning + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated OpenSSH Test OCSP Responder Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +EOF +fi + + +for DIGEST in ${RSA_DIGEST_LIST}; do +( cat << EOF + + +[ CA_OpenSSH_rsa_${DIGEST} ] +EOF + echo_CA_common_options "rsa_${DIGEST}" + cat << EOF +# which md to use: +default_md = ${DIGEST} + +# The private key (!) +private_key = "${SSH_CAKEYDIR}/${CAKEY_PREFIX}-rsa.key" + +#The CA certificate (!) +certificate = "${SSH_CACERTDIR}/${CAKEY_PREFIX}-rsa_${DIGEST}.crt.pem" +EOF +) >> "$1" +done + +( cat << EOF + + +[ CA_OpenSSH_dsa ] +EOF + echo_CA_common_options "dsa" + cat << EOF +# which md to use: +default_md = sha1 + +# The private key (!) +private_key = "${SSH_CAKEYDIR}/${CAKEY_PREFIX}-dsa.key" + +#The CA certificate (!) +certificate = "${SSH_CACERTDIR}/${CAKEY_PREFIX}-dsa.crt.pem" +EOF +) >> "$1" +} + + +# === +cre_db () { +( + var="${SSH_CAROOT}" + + if test ! -d "$var"; then + mkdir -p "$var" || exit $? + else + count=`getNextDirName "${var}"` || exit $? + if test -d "${var}"; then + printf '%s' "saving old directoty as ${attn}${var}.${warn}${count}${norm} ... " + mv "${var}" "${var}.${count}"; show_status $? || exit $? + fi + fi + + mkdir -p "$var" && + mkdir "$var/crt" && + mkdir "$var/crl" || + exit $? + + for type in ${SSH_SIGN_TYPES}; do + create_empty_file "$var/index-${type}.txt" || exit $? + done + + mkdir "$var/newcerts" && + echo '200402160906000001' > "$var/serial" +) +} + + +# === + +cre_config "${TMPDIR}/${CACONFIG}" && +cre_db && +update_file "${TMPDIR}/${CACONFIG}" "${SSH_CACFGFILE}"; retval=$? + +show_status $retval "${extd}Creating${norm} ${warn}TEST${norm} ${attn}Certificate Authority Database${norm}" diff -ruN openssh-4.2p1/tests/CA/2-cre_cakeys.sh openssh-4.2p1+x509-5.5/tests/CA/2-cre_cakeys.sh --- openssh-4.2p1/tests/CA/2-cre_cakeys.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/2-cre_cakeys.sh 2006-03-12 22:39:54.000000000 +0200 @@ -0,0 +1,251 @@ +#! /bin/sh +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Create "Test Certificate Authority" private keys and certificates. +# + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/2-cre_cakeys.sh$//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" + + +OPENSSH_LOG="$CWD/openssh_ca-2.log" +create_empty_file .delmy && +update_file .delmy "$OPENSSH_LOG" > /dev/null || exit $? + + +# === +echo_SSH_CA_DN () { +cat </dev/null + +$OPENSSL genrsa ${RSA_OPT} \ + -passout pass:${KEY_PASS} \ + -out "${TMPDIR}/${CAKEY_PREFIX}-rsa.key" 1024 \ + 2>> "$OPENSSH_LOG" \ +; show_status $? "generating ${extd}TEST CA${norm} ${attn}rsa${norm} private key" \ +|| return $? + +for DIGEST in ${RSA_DIGEST_LIST}; do + +rm -f "${TMPDIR}/${CAKEY_PREFIX}-rsa_${DIGEST}.crt" 2>/dev/null + +echo_SSH_CA_DN "rsa_${DIGEST}" | +$OPENSSL req \ + -new -x509 \ + -config "${SSH_CACFGFILE}" \ + -days $SSH_CACERTDAYS \ + -passin pass:${KEY_PASS} \ + -key "${TMPDIR}/${CAKEY_PREFIX}-rsa.key" \ + -${DIGEST} \ + -out "${TMPDIR}/${CAKEY_PREFIX}-rsa_${DIGEST}.crt" \ + -extensions ca_cert \ + 2>> "$OPENSSH_LOG" \ +; show_status $? "generating ${extd}TEST CA${norm} ${attn}rsa-${DIGEST}${norm} certificate" \ +|| return $? + +done + +return 0 +} + + +# === +gen_dsa () { +DSA_OPT="" +if [ -f /etc/random-seed ]; then + DSA_OPT="${DSA_OPT} -rand /etc/random-seed" +fi + +rm -f "${TMPDIR}/${CAKEY_PREFIX}-dsa.prm" 2>/dev/null +$OPENSSL dsaparam ${DSA_OPT} \ + -out "${TMPDIR}/${CAKEY_PREFIX}-dsa.prm" 1024\ + 2>> "$OPENSSH_LOG";\ +show_status $? "generating ${extd}DSA parameter file${norm}" \ +|| return $? + +rm -f "${TMPDIR}/${CAKEY_PREFIX}-dsa.key" 2>/dev/null +DSA_OPT="${DSA_OPT} -des3" +$OPENSSL gendsa ${DSA_OPT} \ + -passout pass:${KEY_PASS} \ + -out "${TMPDIR}/${CAKEY_PREFIX}-dsa.key" \ + "${TMPDIR}/${CAKEY_PREFIX}-dsa.prm" \ + 2>> "$OPENSSH_LOG" \ +; show_status $? "generating ${extd}TEST CA${norm} ${attn}dsa${norm} private key" \ +|| return $? + + +#request & ceritificate +rm -f "${TMPDIR}/${CAKEY_PREFIX}-dsa.crt" 2>/dev/null + +echo_SSH_CA_DN "dsa" | +$OPENSSL req \ + -new -x509 \ + -config "${SSH_CACFGFILE}" \ + -days $SSH_CACERTDAYS \ + -passin pass:${KEY_PASS} \ + -key "${TMPDIR}/${CAKEY_PREFIX}-dsa.key" \ + -out "${TMPDIR}/${CAKEY_PREFIX}-dsa.crt" \ + -extensions ca_cert \ + 2>> "$OPENSSH_LOG" \ +; show_status $? "generating ${extd}TEST CA${norm} ${attn}dsa-sha1${norm} certificate" \ +|| return $? + +return 0 +} + + +# === +crt2bundle () { +( + val="$1" + test -z "${val}" && { echo ${warn}missing DN${norm} >&2; return 1; } + + echo + echo ${val} + echo ${val} | sed -e 's/./=/g' + $OPENSSL x509 -inform PEM -in "${2}" -fingerprint -noout || exit $? + echo PEM data: + $OPENSSL x509 -inform PEM -in "${2}" -trustout || exit $? + echo Certificate Ingredients: + $OPENSSL x509 -inform PEM -in "${2}" -text -noout || exit $? + + exit 0 +) +} + + +# === +install () { +( + for D in \ + "${SSH_CAROOT}" \ + "${SSH_CAKEYDIR}" \ + "${SSH_CACERTDIR}" \ + ; do + if test ! -d "$D"; then + mkdir -p "${D}" || exit $? + fi + done + chmod 700 "${SSH_CAKEYDIR}" || exit $? + + update_file "${TMPDIR}/${CAKEY_PREFIX}-dsa.prm" "${SSH_CAROOT}/${CAKEY_PREFIX}-dsa.prm" && + for type in rsa dsa; do + F="${CAKEY_PREFIX}-${type}.key" + update_file "${TMPDIR}/${F}" "${SSH_CAKEYDIR}/${F}" && + chmod 400 "${SSH_CAKEYDIR}/${F}" || exit $? + done + + for type in ${SSH_SIGN_TYPES}; do + F="${CAKEY_PREFIX}-${type}.crt" + update_file "${TMPDIR}/${F}" "${SSH_CACERTDIR}/${F}.pem" || exit $? + done + + create_empty_file "${TMPDIR}/${CACERTFILE}" && + for type in ${SSH_SIGN_TYPES}; do + F="${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" + crt2bundle "${SSH_DN_O}-${type}" "${F}" >> "${TMPDIR}/${CACERTFILE}" || exit $? + done + + update_file "${TMPDIR}/${CACERTFILE}" "${SSH_CAROOT}/${CACERTFILE}" +) +} + + +# === +cre_hash_link () { +( +#option -noout problem: +#exit code from .../openssl ... -noout ... is sometime nonzero !!! +#might only by .../openssl x509 ... -noout ... exit code is zero +#sample: +#a) exit code is one - INCORRECT +# .../openssl crl -in a_crl_file -hash -noout +#b) exit code is zero - correct +# .../openssl crl -in a_crl_file -hash -out /dev/null +# +#work around might is to use -out /dev/null :-/ + HASH=`$OPENSSL x509 -in "$1" -noout -hash` || exit $? + NAME=`getNextFreeName ${HASH}.` || exit $? + + echo "creating link ${attn}${NAME}${norm} to ${attn}$1${norm}" + rm -f "${NAME}" && + ln -s "$1" "${NAME}" || exit $? + #link might never fail ;-( + test -h "${NAME}" +) +} + + +cre_hashs () { +#(!) openssl script "c_rehash" is missing in some installations :-( +# c_rehash "${SSH_CACERTDIR}" +( + cd "${SSH_CACERTDIR}" || exit $? + + for F in [0-9a-f]*.[0-9]; do + # we must use test -L, but on ?-OSes ... :-( + if test -h "$F"; then + rm -f "$F" || exit $? + fi + done + + for type in ${SSH_SIGN_TYPES}; do + cre_hash_link "${CAKEY_PREFIX}-${type}.crt.pem" || exit $? + done + + exit 0 +) +} + + +# === + +gen_rsa && +gen_dsa && +install && +cre_hashs; retval=$? + +show_status $retval "${extd}Creating${norm} ${warn}TEST${norm} ${attn}Certificate Authority${norm}" +echo "${warn}password for all private keys is ${attn}${KEY_PASS}${norm}" +exit $retval diff -ruN openssh-4.2p1/tests/CA/3-cre_certs.sh openssh-4.2p1+x509-5.5/tests/CA/3-cre_certs.sh --- openssh-4.2p1/tests/CA/3-cre_certs.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/3-cre_certs.sh 2006-02-16 22:07:11.000000000 +0200 @@ -0,0 +1,273 @@ +#! /bin/sh +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Create certificate(s). +# + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/3-cre_certs.sh$//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" + +usage () { + cat < + -f[ile] [ssh]key_file_name + -t[ype] certificate type: client, server, ocsp(if enabled) + -n[ame] "base" common name +EOF + exit 1 +} + +test "x$TEST_SSH_SSHKEYGEN" = "x" && { echo "Please define TEST_SSH_SSHKEYGEN"; exit 1; } +test -z "$1" && usage + +while test -n "$1"; do + case $1 in + -f|\ + -file) + shift + if test -z "$1"; then + usage + fi + if test -n "${SSH_BASE_KEY}"; then + usage + fi + SSH_BASE_KEY="$1" + shift + ;; + + -t|\ + -type) + shift + if test -z "$1"; then + usage + fi + if test -n "$SSH_CERT_TYPE"; then + usage + fi + SSH_CERT_TYPE="$1" + shift + case $SSH_CERT_TYPE in + client) + SSH_X509V3_EXTENSIONS="usr_cert" + ;; + server) + SSH_X509V3_EXTENSIONS="srv_cert" + ;; + ocsp) + if test "x$SSH_OCSP" = "xyes"; then + SSH_X509V3_EXTENSIONS="ocsp_cert" + else + echo "${warn}unsupported type${norm}" + usage + fi + ;; + *) + echo "${warn}wrong type${norm}" + usage + ;; + esac + ;; + + -n|\ + -name) + shift + if test -z "$1"; then + usage + fi + if test -n "${SSH_BASE_DN_CN}"; then + usage + fi + SSH_BASE_DN_CN="$1" + shift + ;; + + *) + usage + ;; + esac +done + +test -z "${SSH_BASE_KEY}" && usage +test ! -r "${SSH_BASE_KEY}" && { error_file_not_readable; exit 1; } +test -z "${SSH_BASE_DN_CN}" && usage +test -z "${SSH_CERT_TYPE}" && usage + + +OPENSSH_LOG="$CWD/openssh_ca-3.${SSH_BASE_KEY}.${SSH_X509V3_EXTENSIONS}.log" +create_empty_file .delmy && +update_file .delmy "$OPENSSH_LOG" > /dev/null || exit $? + + +# === +cre_csr () { + echo "=== create a new CSR ===" >> "$OPENSSH_LOG" + ( + if test "$SSH_X509V3_EXTENSIONS" != "usr_cert"; then + SSH_DN_EM="." + fi + + cat <> "$OPENSSH_LOG" \ + ; show_status $? "- ${extd}CSR${norm}" +} + + +# === +cre_crt () { + echo "=== create a new CRT ===" >> "$OPENSSH_LOG" + $OPENSSL ca \ + -config "${SSH_CACFGFILE}" \ + -batch \ + -in "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.csr" \ + -name "CA_OpenSSH_${type}" \ + -passin pass:$KEY_PASS \ + -out "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.crt" \ + -extensions ${SSH_X509V3_EXTENSIONS} \ + 2>> "$OPENSSH_LOG" \ + ; show_status $? "- ${extd}CRT${norm}" || + { retval=$? + printf '%s' "${warn}" + grep 'ERROR:' "$OPENSSH_LOG" + printf '%s' "${norm}" + return $retval + } + + sync + $OPENSSL verify \ + -CAfile "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" \ + "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.crt" && + rm -f "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.csr" || + return $? + + printf '%s' '- ' && + update_file \ + "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.crt" \ + "${SSH_BASE_KEY}-${type}${subtype}.crt" +} + + +# === +cre_OpenSSH_Crt () { + printf '%s' "- ${extd}OpenSSH certificate${norm}" + ( cat "${SSH_BASE_KEY}" + $OPENSSL x509 -in "${SSH_BASE_KEY}-${type}${subtype}.crt" -subject -issuer -alias + ) > "${SSH_BASE_KEY}-${type}${subtype}" && + chmod 600 "${SSH_BASE_KEY}-${type}${subtype}" \ + ; show_status $? +} + + +cre_OpenSSH_PubKey () { + printf '%s' "- ${extd}OpenSSH public key${norm}" + "$TEST_SSH_SSHKEYGEN" -y -f "${SSH_BASE_KEY}-${type}${subtype}" \ + > "${SSH_BASE_KEY}-${type}${subtype}.pub" \ + ; show_status $? +} + + +cre_P12_Crt () { + printf '%s' "- ${extd}PKCS #12${norm} file" + $OPENSSL pkcs12 \ + -passin pass:"" \ + -passout pass:"" \ + -in "${SSH_BASE_KEY}-${type}${subtype}" \ + -out "${SSH_BASE_KEY}-${type}${subtype}".p12 \ + -export \ + ; show_status $? +} + + +revoke_crt () { + echo "=== revoke a CRT ===" >> "$OPENSSH_LOG" + printf '%s' "- ${extd}revoke${norm} certificate" + $OPENSSL ca \ + -config "${SSH_CACFGFILE}" \ + -name "CA_OpenSSH_${type}" \ + -passin pass:$KEY_PASS \ + -revoke "${SSH_BASE_KEY}-${type}${subtype}.crt" \ + 2>> "$OPENSSH_LOG" \ + ; show_status $? +} + + +# === +cre_all2 () { + echo + printf '%s\n' "creating ${extd}${SSH_X509V3_EXTENSIONS}${norm} for ${extd}${SSH_BASE_DN_CN}${norm}(${attn}${type}${norm}${warn}${subtype}${norm}) ..." + + cre_csr && + cre_crt || return $? + + test "$SSH_X509V3_EXTENSIONS" = "ocsp_cert" && return 0 + + cre_OpenSSH_Crt && + cre_OpenSSH_PubKey && + cre_P12_Crt +} + + +# === +cre_all () { +( + subtype="" + for type in ${SSH_SIGN_TYPES}; do + cre_all2 || exit $? + done + + test "$SSH_X509V3_EXTENSIONS" = "srv_cert" && exit 0 + + subtype="-revoked" + for type in ${SSH_SIGN_TYPES}; do + cre_all2 && + revoke_crt || exit $? + done + + exit 0 +) +} + +# === + +cre_all; retval=$? + +echo +show_status $retval "${extd}Creating${norm} ${attn}${SSH_BASE_DN_CN}${norm} group of ${warn}test${norm} certificates" diff -ruN openssh-4.2p1/tests/CA/4-cre_crls.sh openssh-4.2p1+x509-5.5/tests/CA/4-cre_crls.sh --- openssh-4.2p1/tests/CA/4-cre_crls.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/4-cre_crls.sh 2006-02-16 22:07:09.000000000 +0200 @@ -0,0 +1,113 @@ +#! /bin/sh +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Create "Test Certificate Authority" CRLs. +# + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/4-cre_crls.sh$//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" + + +OPENSSH_LOG="$CWD/openssh_ca-4.log" +create_empty_file .delmy && +update_file .delmy "$OPENSSH_LOG" > /dev/null || exit $? + + +# === +cre_crlfile() { +( + type="$1" + + cd "${SSH_CACRLDIR}" || exit $? + + FILE="${CAKEY_PREFIX}-${type}.crl.pem" + + printf '%s' "- ${attn}${type}${norm} certificates" + ${OPENSSL} ca \ + -config "${SSH_CACFGFILE}" \ + -name "CA_OpenSSH_${type}" \ + -passin pass:${KEY_PASS} \ + -gencrl \ + -out "${FILE}" \ + 2>> "$OPENSSH_LOG" \ + ; show_status $? || exit $? + + HASH=`${OPENSSL} crl -out /dev/null -in "${FILE}" -hash 2>> "$OPENSSH_LOG"` || exit $? + + NAME=`getNextFreeName "${HASH}.r"` || exit $? + + ln -s "${FILE}" "${NAME}" + #link might never fail :-( + test -h "${NAME}" +) +} + + +# === +cre_crlindir () { + echo "=== create a new CRL ===" >> "$OPENSSH_LOG" + rm -f "${SSH_CACRLDIR}"/* 2>/dev/null + + printf '%s\n' "creating ${extd}CA CRL file${norm} for ..." + for type in ${SSH_SIGN_TYPES}; do + cre_crlfile "${type}" || return $? + done + + return 0 +} + + +# === +cre_CAcrlfile () { +( + crlfile="${SSH_CAROOT}/${CACRLFILE}" + + create_empty_file "${crlfile}" && + for type in ${SSH_SIGN_TYPES}; do + ( ${OPENSSL} crl \ + -in "${SSH_CACRLDIR}/${CAKEY_PREFIX}-${type}.crl.pem" \ + -text \ + 2>> "$OPENSSH_LOG" + echo; echo + ) >> "${crlfile}" || exit $? + done + + exit 0 +) +} + + +# === +cre_all () { + cre_crlindir || return $? + + printf '%s' "creating ${extd}CA CRL ${attn}common${norm} ${extd}file${norm} ..." + cre_CAcrlfile; show_status $? +} + + +# === +cre_all; retval=$? + +show_status $retval "${extd}Creating${norm} ${warn}TEST${norm} ${attn}Certificate Authority${norm} CRL files" diff -ruN openssh-4.2p1/tests/CA/5-cre_ldap.sh openssh-4.2p1+x509-5.5/tests/CA/5-cre_ldap.sh --- openssh-4.2p1/tests/CA/5-cre_ldap.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/5-cre_ldap.sh 2006-02-16 22:07:07.000000000 +0200 @@ -0,0 +1,122 @@ +#! /bin/sh +# Copyright (c) 2004-2005 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Create LDAP files. +# + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/5-cre_ldap.sh$//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" +. ./env + + +if test ! -d ldap/data; then + mkdir -p ldap/data || exit $? +fi + + +# === +cre_base_ldif() { +( + cat < ldap/base.ldif +} + + +# === +cre_slapdconf () { +( + cat < ldap/slapd.conf.tmpl + +} + + +# === + +cre_base_ldif && +cre_slapdconf && +: ; retval=$? + +show_status $retval "${extd}Creating${norm} ${warn}LDAP${norm} ${attn}files${norm}" diff -ruN openssh-4.2p1/tests/CA/config openssh-4.2p1+x509-5.5/tests/CA/config --- openssh-4.2p1/tests/CA/config 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/config 2006-05-01 23:46:27.000000000 +0300 @@ -0,0 +1,178 @@ +# Copyright (c) 2002-2006 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: OpenSSH CA configuration. +# + + +# === main variables: +# on some system (with pam?, AIX?, when port is below 1024, etc.) we +# might use sudo command to start sshd when current user isn`t root or +# to run tests as root. +# Prefered user for tests is NOT root :-) ! +SUDO= +#SUDO=sudo + + +#Old BSD shells, including the Ultrix `sh', don't accept the colon +#for any shell substitution, and complain and die. +##TMPDIR="${TMPDIR:-/tmp}" + +if test -n "$TMPDIR"; then + if test ! -d "$TMPDIR"; then + echo "error: $TMPDIR is not directory" + exit 1 + fi + if test ! -w "$TMPDIR"; then + echo "error: $TMPDIR is not writable" + exit 1 + fi +else + for D in /tmp /var/tmp /usr/tmp; do + test -d $D || continue + test -w $D || continue + TMPDIR=$D + break + done + if test -z "$TMPDIR"; then + echo "error: cannot set TMPDIR" + exit 1 + fi +fi + + +if test -z "${SSH_X509TESTS}"; then +SSH_X509TESTS="\ + blob_auth + dn_auth_file + dn_auth_path + agent + crl + self + alg + ocsp + by_ldap +" +fi + + +# === openssl: + +if test -z "${OPENSSL}"; then + OPENSSL=`which openssl 2>/dev/null` + if test -z "${OPENSSL}"; then + echo "error:cannot find openssl is your path !" >&2 + exit 1 + fi +fi + +printf 'OpenSSL executable version: ' +"${OPENSSL}" version || exit $? + +# These are the known patent issues with OpenSSL: +# name # expires +# mdc2: 4,908,861 13/03/2007 +# idea: 5,214,703 25/05/2010 +# rc5: 5,724,428 03/03/2015 + +if test -z "${RSA_DIGEST_LIST}"; then + for DIGEST in md5 sha1 md2 md4 rmd160; do + if "${OPENSSL}" dgst -${DIGEST} "${OPENSSL}" >/dev/null 2>&1; then + RSA_DIGEST_LIST="${RSA_DIGEST_LIST} ${DIGEST}" + fi + done +fi +if test -z "${RSA_DIGEST_LIST}"; then + echo "RSA_DIGEST_LIST is empty" >&2 + exit 1 +fi +echo "RSA digest list: ${RSA_DIGEST_LIST}" + + +SSH_SIGN_TYPES="" +for DIGEST in ${RSA_DIGEST_LIST}; do + SSH_SIGN_TYPES="${SSH_SIGN_TYPES} rsa_${DIGEST}" +done + SSH_SIGN_TYPES="${SSH_SIGN_TYPES} dsa" + + +# === server section: + +if test -z "${SSHD_PORT}"; then + SSHD_PORT=20022 +fi + +SSHD_LISTENADDRESS=127.0.0.1 +#SSHD_LISTENADDRESS=::1 + +#"yes" or "no" +SSHSERVER_USEPRIVILEGESEPARATION="yes" +#SSHSERVER_USEPRIVILEGESEPARATION="no" + +SSHSERVER_SYSLOGFACILITY=AUTH +SSHSERVER_LOGLEVEL=FATAL +#SSHSERVER_SYSLOGFACILITY=LOCAL3 +#SSHSERVER_LOGLEVEL=DEBUG3 + + +# === certificates: + +KEY_PASS="change_it" +CAKEY_PREFIX="catest" + +SSH_CAROOT="`pwd`/ca-test" +SSH_CAKEYDIR="${SSH_CAROOT}/keys" + +CACERTFILE="catest-bundle.crt" +CACRLFILE="catest-bundle.crl" + +SSH_CACERTDIR="${SSH_CAROOT}/crt" +SSH_CACRLDIR="${SSH_CAROOT}/crl" + +CACONFIG="catest.config" +SSH_CACFGFILE="${SSH_CAROOT}/${CACONFIG}" + +SSH_CACERTDAYS=60 + +SSH_DN_C="XX" +SSH_DN_ST="World" +SSH_DN_L="Somewhere" +SSH_DN_O="OpenSSH Test Team" +SSH_DN_OU="OpenSSH Testers" +SSH_DN_EM="email@not.set" + +# OpenSSL OCSP test responders listen on BASE, BASE+1, ... +if test -z "${SSH_VA_BASEPORT}"; then + SSH_VA_BASEPORT=20080 +fi + +# OpenSSL OCSP responder don't use SO_REUSEADDR :-(, so ocsp tests +# must wait socket to close. +SSH_OPENSLL_OCSP_TMOUT=60 + +# === LDAP: +#SSH_LDAP_DB=bdb +SSH_LDAP_DB=ldbm +SSH_LDAP_DC="dc=example,dc=com" + +if test -z "${LDAPD_PORT}"; then + LDAPD_PORT=20389 +fi +LDAPD_URL="ldap://${SSHD_LISTENADDRESS}:${LDAPD_PORT}" diff -ruN openssh-4.2p1/tests/CA/env.in openssh-4.2p1+x509-5.5/tests/CA/env.in --- openssh-4.2p1/tests/CA/env.in 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/env.in 2004-10-29 22:52:46.000000000 +0300 @@ -0,0 +1,4 @@ +# LDAP environment: +@LDAP_ON@LDAP_SYSCONFDIR="@LDAP_SYSCONFDIR@" +@LDAP_ON@LDAP_LIBEXECDIR="@LDAP_LIBEXECDIR@" +@LDAP_ON@LDAP_BINDIR="@LDAP_BINDIR@" diff -ruN openssh-4.2p1/tests/CA/functions openssh-4.2p1+x509-5.5/tests/CA/functions --- openssh-4.2p1/tests/CA/functions 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/functions 2005-05-30 22:28:13.000000000 +0300 @@ -0,0 +1,264 @@ +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Usefull functions. +# + + +# === +# +# define colors and more for echo commands +# +# \033 ascii ESCape +# \033[G move to column (linux console, xterm, not vt100) +# \033[C move columns forward but only upto last column +# \033[D move columns backward but only upto first column +# \033[A move rows up +# \033[B move rows down +# \033[1m switch bold on +# \033[31m switch red on +# \033[32m switch green on +# \033[33m switch yellow on +# \033[m switch color/bold off +# \017 exit alternate mode (xterm, vt100, linux console) +# \033[10m exit alternate mode (linux console) +# \015 carriage return (without newline) +# + +if test -z "${LINES}" -o -z "${COLUMNS}" ; then + eval `stty size 2>/dev/null | (read L C; \ + if test x${L} = x; then L=24; fi; \ + if test x${C} = x; then C=80; fi; \ + echo LINES=${L} COLUMNS=${C} )` +fi +test ${LINES} -eq 0 && LINES=24 +test ${COLUMNS} -eq 0 && COLUMNS=80 +export LINES COLUMNS + +if test "${TERM}" != "dumb" ; then + esc=`printf '\033'` + extd="${esc}[1m" + warn="${esc}[1;31m" + done="${esc}[1;32m" + attn="${esc}[1;34m" + norm=`printf '%s\017' "${esc}[m"` + stat=`printf '\015%s' "${esc}[${COLUMNS}C${esc}[10D"` + + msg_done="${stat}${done}done${norm}" + msg_failed="${stat}${warn}failed${norm}" + +else + esc="" + extd="" + warn="" + done="" + attn="" + norm="" + stat="" + + msg_done="..done" + msg_failed="..failed" + +fi + + +# === +error_file_not_found () { + echo "${warn}file ${attn}${1}${warn} not found${norm}" + return 1 +} + + +# === +error_file_not_readable () { + echo "${warn}file ${attn}${1}${warn} not found or not readable${norm}" + return 1 +} + + +# === +error_dir_not_found () { + echo "${warn}directory ${attn}${1}${warn} not found${norm}" + return 1 +} + + +# === +printSeparator() { + echo "=======================================================================" +} + + +# === +show_status () { + if test -n "$2"; then + printf '%s' "$2" + fi + if test $1 -eq 0; then + echo "$msg_done" + else + echo "$msg_failed" + fi + return $1 +} + + +# === +getNextFreeName() { + var="$1" + limit="$2" + + if test -z "${limit}"; then + limit=10 + fi + + count=0 + while true; do + test ! -f "${var}${count}" && break + count=`expr ${count} + 1` + if test ${count} -ge ${limit}; then + echo "getNextFreeName: ${warn}limit reached${norm} for file ${attn}${var}${norm}" >&2 + + echo "" + return 33 + fi + done + + echo "${var}${count}" + return 0 +} + + +# === +getNextDirName() { + var="$1" + count=0 + while true; do + test ! -d "${var}.${count}" && break + count=`expr ${count} + 1` + done + if test ${count} -ge 10; then + echo "${warn}please remove ${attn}${var}${warn} backup directories !${norm}" >&2 + return 33 + fi + echo $count + return 0 +} + + +# === +create_empty_file () { + cat /dev/null > "$1" +} + + +# === +update_file () { + var_new="$1" + var_old="$2" + + if test ! -f "${var_old}"; then + printf '%s' "creating file ${attn}${var_old}${norm}" + mv "${var_new}" "${var_old}"; show_status $? + return $? + fi + test -r "${var_new}" || { error_file_not_readable "${var_new}"; return 1; } + + if diff "${var_old}" "${var_new}" >/dev/null 2>&1; then + echo "no changes in ${attn}${var_old}${norm}" + rm -f "${var_new}" + return 0 + fi + + backup=`getNextFreeName "${var_old}."` || return $? + printf '%s' "saving old file as ${attn}${backup}${norm}" + cp -p "${var_old}" "${backup}"; show_status $? || return $? + + printf '%s' "updating file ${attn}${var_old}${norm}" + if test ! -w "${var_old}"; then + chmod u+w "${var_old}" + not_writable="yes" + fi + cat "${var_new}" > "${var_old}"; show_status $? || return $? + if test "$not_writable" = "yes"; then + chmod u-w "${var_old}" + fi + rm -f "${var_new}" + return 0 +} + + +# === +getSSHkeyType () { + identity_file="$1" + if test ! -r "$identity_file"; then + error_file_not_readable "${identity_file}" >&2; return $? + fi + + sshkeytype="unspec" + retval=0 + + sshkeytype=`"${TEST_SSH_SSHKEYGEN}" -f "${identity_file}" -y 2>/dev/null`; retval=$? + if test $retval -ne 0 ; then + echo "${warn}command${norm} ${TEST_SSH_SSHKEYGEN} ${warn}fail${norm}" >&2 + return $retval + fi + echo "${sshkeytype}" | cut -d ' ' -f 1 + return 0 +} + + +# === +getSubject () { + identity_file="$1" +#rest of arguments passed to openssl + + if test ! -r "$identity_file"; then + error_file_not_readable "${identity_file}" >&2 + return 1 + fi + shift + + retval=0 + +#SHELL bug or ?: when we assign command result to "local xxx=..." retval is always zero :-/ !!! +#unix sh don't like local :-) +# local subject=`"${OPENSSL}" x509 -noout -subject -in "${identity_file}" $*`; retval=$? + subject=`"${OPENSSL}" x509 -noout -subject -in "${identity_file}" $* 2>/dev/null`; retval=$? + if test $retval -ne 0 ; then + echo "${warn}cannot get certificate subject${norm}" >&2 + return $retval + fi + echo "$subject" | cut -d ' ' -f 2- +} + + +#=== +creX509AuthorizedKeysFile () { + identity_file="$1" + + sshkeytype=`getSSHkeyType "${identity_file}"` || return $? + subject=`getSubject "${identity_file}"` || return $? + echo "${sshkeytype} subject ${subject}" > "${AUTHORIZEDKEYSFILE}" +} + + +# === +FUNCTIONS_INCLUDED="yes" diff -ruN openssh-4.2p1/tests/CA/Makefile.in openssh-4.2p1+x509-5.5/tests/CA/Makefile.in --- openssh-4.2p1/tests/CA/Makefile.in 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/Makefile.in 2005-08-10 21:02:59.000000000 +0300 @@ -0,0 +1,134 @@ +srcdir=@srcdir@ +@OCSP_ON@SSH_OCSP=yes +@OCSP_OFF@SSH_OCSP=no +KEYBITS=1024 + + +all: + + +clean: ldap_clean + rm -f testhostkey_* + rm -f testid_* + rm -f testocsp_* + rm -fr ca-test/ + rm -f openssh_ca-?.log* + rm -f openssh_ca-3.*.log* + rm -f va-*.log + rm -f sshd_x509.log + +distclean: clean + rm -f env + rm -f Makefile + +# === + +check-certs: ca_files hostkeys identities ocsp_certs crl_files ldap_files + @echo + $(SHELL) $(srcdir)/openssh_tests.sh + +# === +ca_files: ca-test/catest.config ca-test/catest-bundle.crt + +#user is responsible to recreate X.509 tests files !!! +#ca-test/catest.config: $(srcdir)/config +ca-test/catest.config: + @echo + SSH_OCSP=$(SSH_OCSP) \ + $(SHELL) $(srcdir)/1-cre_cadb.sh + +ca-test/catest-bundle.crt: ca-test/catest.config + @echo + $(SHELL) $(srcdir)/2-cre_cakeys.sh + + +# === +hostkeys: testhostkey_rsa testhostkey_rsa-rsa_md5 testhostkey_dsa testhostkey_dsa-rsa_md5 + +testhostkey_rsa: + @echo + @echo "generating RSA 'hostkey'" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" + +testhostkey_rsa-rsa_md5: testhostkey_rsa ca-test/catest-bundle.crt + @echo + @echo "generating RSA server certificates, keys, etc." + $(SHELL) $(srcdir)/3-cre_certs.sh -f testhostkey_rsa -t server -n "localhost RSA" + +testhostkey_dsa: + @echo + @echo "generating DSA 'hostkey'" + $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" + +testhostkey_dsa-rsa_md5: testhostkey_dsa ca-test/catest-bundle.crt + @echo + @echo "generating DSA server certificates, keys, etc." + $(SHELL) $(srcdir)/3-cre_certs.sh -f testhostkey_dsa -t server -n "localhost DSA" + + +# === +identities: testid_rsa testid_rsa-rsa_md5 testid_dsa testid_dsa-rsa_md5 + +testid_rsa: + @echo + @echo "generating RSA 'Identity'" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" + +testid_rsa-rsa_md5: testid_rsa ca-test/catest-bundle.crt + @echo + @echo "generating RSA client certificates, keys, etc." + $(SHELL) $(srcdir)/3-cre_certs.sh -f testid_rsa -t client -n "OpenSSH RSA test certificate" + +testid_dsa: + @echo + @echo "generating DSA 'Identity'" + $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" + +testid_dsa-rsa_md5: testid_dsa ca-test/catest-bundle.crt + @echo + @echo "generating DSA client certificates, keys, etc." + $(SHELL) $(srcdir)/3-cre_certs.sh -f testid_dsa -t client -n "OpenSSH DSA test certificate" + + +# === +@OCSP_OFF@ocsp_certs: +@OCSP_ON@ocsp_certs: testocsp_rsa-rsa_md5.crt testocsp_dsa-rsa_md5.crt + +@OCSP_ON@testocsp_rsa-rsa_md5.crt: testocsp_rsa ca-test/catest-bundle.crt +@OCSP_ON@ @echo; echo "generating RSA ocsp responder certificates." +@OCSP_ON@ SSH_OCSP=$(SSH_OCSP) \ +@OCSP_ON@ $(SHELL) $(srcdir)/3-cre_certs.sh -f testocsp_rsa -t ocsp -n "validator RSA" + +@OCSP_ON@testocsp_rsa: +@OCSP_ON@ @echo; echo "generating RSA 'ocspkey'" +@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." +@OCSP_ON@ SSH_OCSP=$(SSH_OCSP) \ +@OCSP_ON@ $(SHELL) $(srcdir)/3-cre_certs.sh -f testocsp_dsa -t ocsp -n "validator DSA" + +@OCSP_ON@testocsp_dsa: +@OCSP_ON@ @echo; echo "generating DSA 'ocspkey'" +@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" + + +# === +crl_files: ca-test/catest-bundle.crl + +ca-test/catest-bundle.crl: testid_rsa-rsa_md5 testid_dsa-rsa_md5 + @echo + $(SHELL) $(srcdir)/4-cre_crls.sh + +# === +@LDAP_OFF@ldap_files: +@LDAP_ON@ldap_files: ldap/slapd.conf.tmpl + +@LDAP_ON@ldap/slapd.conf.tmpl: env +@LDAP_ON@ @echo +@LDAP_ON@ $(SHELL) $(srcdir)/5-cre_ldap.sh + +@LDAP_OFF@ldap_clean: +@LDAP_ON@ldap_clean: +@LDAP_ON@ rm -f ldap_setup.log +@LDAP_ON@ rm -fr ldap diff -ruN openssh-4.2p1/tests/CA/openssh_tests.sh openssh-4.2p1+x509-5.5/tests/CA/openssh_tests.sh --- openssh-4.2p1/tests/CA/openssh_tests.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/openssh_tests.sh 2006-04-13 01:40:03.000000000 +0300 @@ -0,0 +1,364 @@ +#! /bin/sh +# Copyright (c) 2002-2006 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Test OpenSSH client and server with x509 certificates. +# + + +CWD=`pwd` +SCRIPTDIR=`echo $0 | sed 's/openssh_tests.sh//'` +. "${SCRIPTDIR}shell.rc" +. "${SCRIPTDIR}functions" +. "${SCRIPTDIR}config" +. "./env" + +test "x$TEST_SSH_SSH" = "x" && { echo "${warn}Please define ${attn}TEST_SSH_SSH${norm}" ; exit 1; } +test "x$TEST_SSH_SSHD" = "x" && { echo "${warn}Please define ${attn}TEST_SSH_SSHD${norm}" ; exit 1; } +test "x$TEST_SSH_SSHAGENT" = "x" && { echo "${warn}Please define ${attn}TEST_SSH_SSHAGENT${norm}" ; exit 1; } +test "x$TEST_SSH_SSHADD" = "x" && { echo "${warn}Please define ${attn}TEST_SSH_SSHADD${norm}" ; exit 1; } +test "x$TEST_SSH_SSHKEYGEN" = "x" && { echo "${warn}Please define ${attn}TEST_SSH_SSHKEYGEN${norm}"; exit 1; } +#TEST_SSH_SSHKEYSCAN +#TEST_SSH_SFTP +#TEST_SSH_SFTPSERVER + + +SSHD_LOG="${CWD}/sshd_x509.log" +SSHD_PID="${CWD}/.sshd_x509.pid" +SSHD_CFG="${CWD}/sshd_config-certTests" +SSH_CFG="${CWD}/ssh_config-certTests" + +SSH_ERRLOG="${CWD}/.ssh_x509.err.log" +SSH_REPLY="${CWD}/.ssh_x509.reply" +SSH_EXTRA_OPTIONS="" + + +TEST_SSH_CLIENTKEYS="\ + testid_rsa + testid_dsa +" + +#OpenSSL OCSP limitation: only rsa keys +#TEST_OCSP_RESPKEYS="\ +# testocsp_rsa +# testocsp_dsa +#" +TEST_OCSP_RESPKEYS="testocsp_rsa" + +#TEST_SSHD_HOSTKEY="${CWD}/testhostkey_rsa-rsa_md5" +TEST_SSHD_HOSTKEY="${CWD}/testhostkey_rsa" + + +USERDIR="${HOME}/.ssh" +if test ! -d "${USERDIR}"; then + mkdir "${USERDIR}" || exit 1 + chmod 700 "${USERDIR}" || exit 1 +fi + +AUTHORIZEDKEYSFILE="${USERDIR}/authorized_keys-certTests" +USERKNOWNHOSTSFILE="${USERDIR}/known_hosts-certTests" + + +# === +# remove unsupported tests + +cat > "$SSHD_CFG" < "${SSHD_LOG}" 2>&1 +if grep 'Unsupported.*CACertificateFile' "${SSHD_LOG}" > /dev/null; then + SSH_X509STORE_DISABLED="yes" +else + SSH_X509STORE_DISABLED="no" +fi +if grep 'Unsupported.*CAldapURL' "${SSHD_LOG}" > /dev/null; then + SSH_LDAP_ENABLED="no" +else + SSH_LDAP_ENABLED="yes" +fi +if grep 'Unsupported.*VAType' "${SSHD_LOG}" > /dev/null; then + SSH_OCSP_ENABLED="no" +else + SSH_OCSP_ENABLED="yes" +fi + +echo SSH_X509STORE_DISABLED=${SSH_X509STORE_DISABLED} +if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + SSH_X509TESTS=`echo "${SSH_X509TESTS}" | \ + sed \ + -e 's|dn_auth_file||g' \ + -e 's|dn_auth_path||g' \ + -e 's|crl||g' \ + -e 's|self||g'` +fi +echo SSH_LDAP_ENABLED=${SSH_LDAP_ENABLED} +if test "x${SSH_LDAP_ENABLED}" = "xno"; then + SSH_X509TESTS=`echo "${SSH_X509TESTS}" | sed -e 's|by_ldap||g'` +fi +echo SSH_OCSP_ENABLED=${SSH_OCSP_ENABLED} +if test "x${SSH_OCSP_ENABLED}" = "xno"; then + SSH_X509TESTS=`echo "${SSH_X509TESTS}" | sed -e 's|ocsp||g'` +fi +echo SSH_X509TESTS=$SSH_X509TESTS + + +# === +runSSHdaemon() { + echo "=======================================================================" >> "${SSHD_LOG}" + + if test -f "${SSHD_PID}"; then + echo "${warn}sshd pid file exist!${norm}" >&2 + fi + + #NOTES: + #- without -d option sshd run in daemon mode and this command always return 0 !!! + #- bug or ?: with option -e no log to stderr in daemon mode + $SUDO "$TEST_SSH_SSHD" -f "${SSHD_CFG}" \ + -o PidFile="${SSHD_PID}" \ + -o SyslogFacility="${SSHSERVER_SYSLOGFACILITY}" \ + -o LogLevel="${SSHSERVER_LOGLEVEL}" \ + >> "${SSHD_LOG}" 2>&1 + + sleep 3 + if test ! -f "${SSHD_PID}"; then + printf "${warn}cannot start sshd:${norm} " >&2 + error_file_not_readable "${SSHD_PID}" + return 33 + fi +} + + +# === +killSSHdaemon() { +( + $SUDO kill `cat "${SSHD_PID}" 2>/dev/null` > /dev/null 2>&1 + K=0 + while test $K -le 9; do + if test ! -f "${SSHD_PID}"; then + break + fi + sleep 1 + K=`expr $K + 1` + done + rm -f "${SSHD_CFG}" + if test -f "${SSHD_PID}"; then + $SUDO kill -9 `cat "${SSHD_PID}" 2>/dev/null` > /dev/null 2>&1 + sleep 1 + $SUDO rm -f "${SSHD_PID}" > /dev/null 2>&1 + fi + exit 0 +) +} + + +# === +testEND() { + ( echo + echo "*=- The END -=*" + ) >> "${SSHD_LOG}" + + rm -f "${SSH_ERRLOG}" + rm -f "${SSH_REPLY}" + rm -f "${AUTHORIZEDKEYSFILE}" + rm -f "${USERKNOWNHOSTSFILE}" + rm -f "${SSH_CFG}" +} + +testBREAK() { + ( echo + echo "*=- BREAK -=*" + ) >> "${SSHD_LOG}" + killSSHdaemon +} + +trap testBREAK INT QUIT ABRT KILL TERM || exit 1 +trap testEND EXIT || exit 1 + + +# === +creTestSSHDcfgFile() { + cat > "${SSHD_CFG}" < "${SSH_CFG}" <> "${SSH_CFG}" < "${SSH_ERRLOG}" > "${SSH_REPLY}"; retval=$? + + if test "x$must_fail" = "x1"; then + if test $retval -ne 0; then + retval=0 + else + retval=1 + fi + fi + + show_status $retval + if test $retval -ne 0; then + printf '%s' "${warn}" + cat "${SSH_ERRLOG}"; printf '%s' "${norm}" + else + if test "x$must_fail" = "x1"; then + if fgrep 'Permission denied (publickey)' "${SSH_ERRLOG}" > /dev/null; then + printf '%s' "${done}" + else + retval=33 + printf '%s' "${warn}" + fi + cat "${SSH_ERRLOG}"; printf '%s' "${norm}" + else + if fgrep "$msg" "${SSH_REPLY}" > /dev/null; then + : + else + retval=33 + printf '%s' "${warn}" + cat "${SSH_REPLY}"; printf '%s' "${norm}" + fi + fi + fi + + exit $retval +) +} + + +# === +do_all () { + create_empty_file "${AUTHORIZEDKEYSFILE}" && + chmod 644 "${AUTHORIZEDKEYSFILE}" || return $? + + create_empty_file "${SSHD_LOG}" || return $? + + if test ! -f "${TEST_SSHD_HOSTKEY}.pub"; then + echo "${warn}Public host file ${attn}${TEST_SSHD_HOSTKEY}.pub${warn} not found !${norm}" + return 3 + fi + ( printf '%s' "${SSHD_LISTENADDRESS} " + cat "${TEST_SSHD_HOSTKEY}.pub" + ) > "${USERKNOWNHOSTSFILE}" && + chmod 644 "${USERKNOWNHOSTSFILE}" || return $? + + # call the test scripts + for LTEST in ${SSH_X509TESTS}; do + ( + echo + echo "using: ${attn}${SCRIPTDIR}test-${LTEST}.sh.inc${norm}" + . ${SCRIPTDIR}test-${LTEST}.sh.inc && + do_test + ) || return $? + done + + printSeparator + return 0 +} + + +# === +echo +printSeparator +echo "${extd}Testing OpenSSH client and server with certificates:${norm}" +printSeparator + +do_all; retval=$? + +echo +printSeparator +echo "${extd}Testing OpenSSH client and server with certificates finished.${norm}" +show_status $retval " ${extd}status${norm}:" +printSeparator +echo + +exit $retval diff -ruN openssh-4.2p1/tests/CA/shell.rc openssh-4.2p1+x509-5.5/tests/CA/shell.rc --- openssh-4.2p1/tests/CA/shell.rc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/shell.rc 2006-02-16 22:40:27.000000000 +0200 @@ -0,0 +1,34 @@ +# Copyright (c) 2003-2006 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Shell settings. +# + + +# Be Bourne compatible (as autoconf do it) +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi diff -ruN openssh-4.2p1/tests/CA/test-agent.sh.inc openssh-4.2p1+x509-5.5/tests/CA/test-agent.sh.inc --- openssh-4.2p1/tests/CA/test-agent.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/test-agent.sh.inc 2006-02-05 18:24:05.000000000 +0200 @@ -0,0 +1,165 @@ +# +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Test OpenSSH client authentication: +# - add a key to agent; +# - list agent keys; +# - try to connect with key from agent; +# - remove the key from agent. +# + + +# === +#env. vars: +# SSH_CLIENTKEY +# type +testAgent () { + identity_file="${SSH_CLIENTKEY}-${type}" + if test ! -r "${identity_file}"; then + error_file_not_readable "${identity_file}"; return $? + fi + + ( + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + cat "${identity_file}.pub" + else + sshkeytype=`getSSHkeyType "${identity_file}"` || exit $? + subject=`getSubject "${identity_file}"` || exit $? + + echo "${sshkeytype} Subject: ${subject}" + fi + ) > "${AUTHORIZEDKEYSFILE}" || return $? + +( +killAgent () { + "${TEST_SSH_SSHAGENT}" -k > /dev/null + sleep 1 + exit $1 +} + +checkEmptyListResponse () { + case $1 in + 1) return 0;; + 0) killAgent 99;; + *) killAgent $1;; + esac + return 33 +} + +showAgentMsg() { + show_status $1 "$2" + if test $1 -ne 0; then + printf '%s' "${warn}" + cat "${SSH_ERRLOG}" + printf '%s' "${norm}" + if test $1 -ne 2; then + killAgent $1 + fi + exit $1 + fi + + if test "x$3" != "x"; then + printf '%s' "${done}" + cat "$3" + printf '%s' "${norm}" + fi + return 0 +} + + eval `"${TEST_SSH_SSHAGENT}"` > /dev/null + + "${TEST_SSH_SSHADD}" -L >/dev/null; checkEmptyListResponse $? + + "${TEST_SSH_SSHADD}" "${identity_file}" 2> "${SSH_ERRLOG}" > "${SSH_REPLY}"; \ + showAgentMsg $? " add identity ${extd}${SSH_CLIENTKEY}-${attn}${type}${norm} to agent ..." + + "${TEST_SSH_SSHADD}" -L 2> "${SSH_ERRLOG}" > "${SSH_REPLY}"; \ + retval=$? + if test $retval -ne 0; then + showAgentMsg ${retval} + else + printf " ${done}-${norm} " + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + printf '%s.......\n' "`cut -c -60 \"${SSH_REPLY}\"`" + else + cat "${SSH_REPLY}" + fi + fi + +# TODO +# Note the current script run ssh with -i option, +# but ssh check existence of file and when file +# don't exit it is excluded form list of identity +# files. When the list is empty ssh will use +# default file names. To avoid this we will +# use /dev/null, until method runTest run ssh +# with -i option +#!!! "use-only-key-from-agent" \ + runTest "${type}" \ + "/dev/null" \ + "key from agent ..." || + killAgent $? + + "${TEST_SSH_SSHADD}" -d "${identity_file}".pub \ + 2> "${SSH_ERRLOG}" > "${SSH_REPLY}"; \ + showAgentMsg $? " remove identity ${extd}${SSH_CLIENTKEY}-${attn}${type}${norm} from agent ..." + + "${TEST_SSH_SSHADD}" -L > /dev/null; checkEmptyListResponse $? + + killAgent 0 +) +} + + +# === + +do_test () { + retval=0 + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + echo "* ${extd}with x509 identity from ${attn}agent${norm}:" + else + echo "* ${extd}against ${attn}CACertificateFile${norm} and x509 identity from ${attn}agent${norm}:" + fi + + creTestSSHDcfgFile + if test "x${SSH_X509STORE_DISABLED}" != "xyes"; then + cat >> "$SSHD_CFG" <> "$SSHD_CFG" <> "$SSHD_CFG" </dev/null > "${AUTHORIZEDKEYSFILE}" || exit $? + + if test -n "$must_fail"; then + typemsg="${identity_file} ${warn}!${norm}" + else + typemsg="${identity_file}" + fi + runTest "${typemsg}" \ + "${identity_file}" "" "$must_fail" || exit $? + + for type in ${SSH_SIGN_TYPES}; do + if test -n "$withcert"; then + must_fail="" + case $alg in + x509v3-sign-rsa*) test "$keytype" = "rsa" || must_fail="yes";; + x509v3-sign-dss*) test "$keytype" = "dsa" || must_fail="yes";; + *) echo "${warn}unknown X.509 alg${norm}" + exit 1;; + esac + else + must_fail="yes" + fi + + identity_file="${SSH_CLIENTKEY}-${type}" + "$TEST_SSH_SSHKEYGEN" -f "${identity_file}" -y 2>/dev/null > "${AUTHORIZEDKEYSFILE}" || exit $? + + if test -n "$must_fail"; then + typemsg="${identity_file} ${warn}!${norm}" + else + typemsg="${identity_file}" + fi + runTest "${typemsg}" \ + "${identity_file}" "" "$must_fail" || exit $? + done + done + ); retval=$? + killSSHdaemon + + return $retval +} + + +# === + +do_test () { + retval=0 + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + echo "* ${extd}with different publickey ${attn}algorithms${norm}:" + else + echo "* ${extd}against ${attn}CACertificateFile${norm} and different publickey ${attn}algorithms${norm}:" + fi + + for alg in \ + "ssh-rsa" \ + "ssh-dss" \ + "x509v3-sign-rsa" \ + "x509v3-sign-dss" \ + ; do + testAlg; retval=$? + if test $retval -ne 0; then + break + fi + done + return $retval +} diff -ruN openssh-4.2p1/tests/CA/test-blob_auth.sh.inc openssh-4.2p1+x509-5.5/tests/CA/test-blob_auth.sh.inc --- openssh-4.2p1/tests/CA/test-blob_auth.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/test-blob_auth.sh.inc 2004-03-08 23:30:24.000000000 +0200 @@ -0,0 +1,84 @@ +# +# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Test OpenSSH client authentication: +# - "IdentityFile" contain private key and x509 certificate; +# - "AuthorizedKeysFile" contain certificate BLOB. +# + + +# === +#env. vars: +# SSH_CLIENTKEY +# type +testBLOBautorization () { + identity_file="${SSH_CLIENTKEY}-${type}" + if test ! -r "${identity_file}"; then + error_file_not_readable "${identity_file}"; return $? + fi + + echo " using identity file ${identity_file}" + echo " creating AuthorizedKeysFile" + "$TEST_SSH_SSHKEYGEN" -f "${identity_file}" -y 2>/dev/null > "${AUTHORIZEDKEYSFILE}" || return $? + runTest "${type}" "${identity_file}"\ + "${extd}valid${norm} blob" || return $? + + blob=`cat "${AUTHORIZEDKEYSFILE}"` + echo $blob | cut -c 1-50 > "${AUTHORIZEDKEYSFILE}" + runTest "${type}" "${identity_file}"\ + "${warn}invalid${norm} blob" "Yes" || return $? +} + + +# === + +do_test () { + retval=0 + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + echo "* ${extd}with autorization by x509 ${attn}blob${norm}:" + else + echo "* ${extd}against ${attn}CACertificateFile${norm} and autorization by x509 ${attn}blob${norm}:" + fi + + creTestSSHDcfgFile + if test "x${SSH_X509STORE_DISABLED}" != "xyes"; then + cat >> "$SSHD_CFG" < ${LDAPD_CFG} +} + + +# === +creTestLDAPDCAldifFile() { +( + for type in ${SSH_SIGN_TYPES}; do + N="${CAKEY_PREFIX}-${type}.crt" + if test ! -f "ldap/${N}.der"; then + ${OPENSSL} x509 \ + -in "${SSH_CACERTDIR}/${N}".pem \ + -out "ldap/${N}.der" -outform DER \ + || exit $? + fi + + N="${CAKEY_PREFIX}-${type}.crl" + if test ! -f "ldap/${N}.der"; then + ${OPENSSL} crl \ + -in "${SSH_CACRLDIR}/${N}".pem \ + -out "ldap/${N}.der" -outform DER \ + || exit $? + fi + done +) || return $? + +( + for type in ${SSH_SIGN_TYPES}; do + cat < ldap/ca.ldif +} + + +# === +runLDAPdaemon() { + if test -f "${LDAPD_PID}"; then + echo "${warn}slapd pid file exist!${norm}" >&2 + fi + + printf ' %s' "starting ${extd}LDAP${norm} server on ${attn}${LDAPD_URL}${norm}" + #for errors check syslog files(LOCAL4 facility) + $SUDO "${LDAP_LIBEXECDIR}/slapd" \ + -f "${LDAPD_CFG}" \ + -h "${LDAPD_URL}" \ + > /dev/null 2>&1 + + sleep 2 + K=0 + while test $K -le 5; do + if test -f "${LDAPD_PID}"; then + break + fi + sleep 1 + K=`expr $K + 1` + done + + test -r "${LDAPD_PID}"; show_status $? + if test ! -r "${LDAPD_PID}"; then + printf "${warn}cannot start slapd:${norm} " >&2 + error_file_not_readable "${LDAPD_PID}" + return 33 + fi + return 0 +} + + +killLDAPdaemon() { +( + $SUDO kill `cat "${LDAPD_PID}" 2>/dev/null` > /dev/null 2>&1 + K=0 + while test $K -le 9; do + if test ! -f "${LDAPD_PID}"; then + break + fi + sleep 1 + K=`expr $K + 1` + done + if test -f "${LDAPD_PID}"; then + $SUDO kill -9 `cat "${LDAPD_PID}" 2>/dev/null` > /dev/null 2>&1 + sleep 1 + $SUDO rm -f "${LDAPD_PID}" > /dev/null 2>&1 + $SUDO rm -f "${LDAPD_ARGS}" > /dev/null 2>&1 + fi + rm -f "${LDAPD_CFG}" + exit 0 +) +} + + +initLDAPdb() { + create_empty_file "${LDAP_SETUP_LOG}" || return $? + + "${LDAPADD}" \ + -x -w secret -D "cn=Manager,${SSH_LDAP_DC}" \ + -H "${LDAPD_URL}" \ + -f "${CWD}/ldap/base.ldif" \ + >> "${LDAP_SETUP_LOG}" 2>&1 || return $? + + "${LDAPADD}" \ + -x -w secret -D "cn=Manager,${SSH_LDAP_DC}" \ + -H "${LDAPD_URL}" \ + -f "${CWD}/ldap/ca.ldif" \ + >> "${LDAP_SETUP_LOG}" 2>&1 || return $? + + return 0 +} + + +# === +# $1 - LDAP version +testLDAP() { + printSeparator + echo "Begin test with LDAP ${extd}version${norm} ${attn}$1${norm}" + + creTestLDAPDcfgFile + creTestLDAPDCAldifFile + creTestSSHDcfgFile + +#openssh config parser limitation +SSH_CONF_LDAP_DC=`echo ${SSH_LDAP_DC} | sed -e 's|=|%3D|g'` + cat >> "$SSHD_CFG" <> "$SSHD_CFG" <> "$SSHD_CFG" <> "$SSHD_CFG" < /dev/null + FILE="${SSH_CACRLDIR}/${CAKEY_PREFIX}-${crltype}.crl.pem" + HASH=`${OPENSSL} crl -out /dev/null -in "${FILE}" -hash`; retval=$? + if test ${retval} -eq 0; then + hashfile="${CRL_TEST_DIR}/${HASH}.r0" + ln -s "${FILE}" "${hashfile}" + #link might never fail :-( + test -h "${hashfile}"; retval=$? + fi + #printf "${norm}" + show_status ${retval} || return $? + + ( + for type in ${SSH_SIGN_TYPES}; do + for SSH_CLIENTKEY in ${TEST_SSH_CLIENTKEYS}; do + identity_file="${SSH_CLIENTKEY}-${type}-revoked" + + creX509AuthorizedKeysFile "${identity_file}" || exit $? + + if test "${type}" = "${crltype}"; then + runTest "${SSH_CLIENTKEY}-${warn}${type}-revoked${norm}" \ + "${identity_file}" "" "Yes" + else + runTest "${identity_file}" \ + "${identity_file}" "" "" + fi || exit $? + done + done + exit 0 + ); retval=$? + + if test ${retval} -eq 0; then + rm -f "${hashfile}"; retval=$? + else + rm -f "${hashfile}" + fi + return ${retval} +} + + +# === +test_onlyonecrl () { + retval=0 + CRL_TEST_DIR="${SSH_CAROOT}/crl-test" + + printSeparator + echo "Check ${extd}revoked${norm} with only ${attn}one CRL${norm} in ${attn}CARevocationPath${norm} ..." + + mkdir -p "${CRL_TEST_DIR}" || return $? + + creTestSSHDcfgFile + cat >> "$SSHD_CFG" < /dev/null + if test ${retval} -eq 0; then + rmdir "${CRL_TEST_DIR}"; retval=$? + else + rmdir "${CRL_TEST_DIR}" + fi + return ${retval} +} + + +# === +test_crlpresence_yes () { + printSeparator + echo "Begin test with mandatory ${extd}CRL presence ${attn}with${norm} CRL ..." + + creTestSSHDcfgFile + cat >> "$SSHD_CFG" <> "$SSHD_CFG" < "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${subtype}" "${identity_file}" "" || return $? + done + + subtype="subject" + subject=`getSubject "${identity_file}" -nameopt RFC2253` || return $? + echo "${sshkeytype} ${subtype} ${subject}" > "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${subtype} in ${attn}RFC2253${norm} format" "${identity_file}" "" || return $? + + echo "${sshkeytype} ${subtype} ${subject}" | sed -e 's/,/\//'> "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${subtype} and mixed item-separator symbol" "${identity_file}" "" || return $? + + for subtype in \ + "Invalid" \ + "Subject-" \ + ; do + echo "${sshkeytype} ${subtype} ${subject}" > "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${warn}${subtype}${norm}" "${identity_file}" \ + "autorization type" "Yes" || return $? + done + + subtype="Subject" + printf "${sshkeytype} ${subtype}," > "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${warn}empty${norm} ${subtype}" "${identity_file}" \ + "" "Yes" || return $? + + subtype="Subject" + ( printf "${sshkeytype} ${subtype}" + echo "${subject}" | cut -c -40 + ) > "${AUTHORIZEDKEYSFILE}" + runTest "${type} ${warn}invalid${norm} ${subtype}" "${identity_file}" \ + "" "Yes" || return $? + + return 0 +} + + +# === + +do_test () { + if test "x${SSH_X509STORE_DISABLED}" = "xyes"; then + echo "* ${extd}X.509 store${norm} is ${attn}disabled${norm}" + return 1 + fi + echo "* ${extd}against ${attn}CACertificateFile${norm} and autorization by x509 ${attn}'Distinguished Name'${norm}:" + + creTestSSHDcfgFile + cat >> "$SSHD_CFG" <> "$SSHD_CFG" </dev/null + + for catype in ${SSH_SIGN_TYPES}; do + F="${SSH_CACERTDIR}/${CAKEY_PREFIX}-${catype}.crt.pem" + HASH=`$OPENSSL x509 -in "${F}" -noout -hash` + ( cd "${CRT_TEST_DIR}" || exit $? + ln -s "${F}" "$HASH.0" + #link might never fail :-( + test -h "$HASH.0" + ) && + do_test_catype; retval=$? + rm -f "${CRT_TEST_DIR}/$HASH.0" + if test $retval -ne 0; then + break + fi + done + + rmdir "${CRT_TEST_DIR}" + if test $retval -ne 0; then + exit $retval + fi + done + + exit 0 + ); retval=$? + killSSHdaemon + return $retval +} diff -ruN openssh-4.2p1/tests/CA/test-ocsp.sh.inc openssh-4.2p1+x509-5.5/tests/CA/test-ocsp.sh.inc --- openssh-4.2p1/tests/CA/test-ocsp.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/tests/CA/test-ocsp.sh.inc 2004-10-16 23:22:25.000000000 +0300 @@ -0,0 +1,255 @@ +# +# Copyright (c) 2004 Roumen Petrov, Sofia, Bulgaria +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 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. +# +# DESCRIPTION: Test OpenSSH client authentication: +# - "IdentityFile" contain private key and x509 certificate; +# - "AuthorizedKeysFile" contain certificate Subject; +# - validation against: +# - OCSP provider from certificate +# - specified in configuration OCSP provider +# - TODO:specified OCSP provider with revoked provider certificate +# Note: +# Due OpenSSL limitation no one of tests start OCSP provider with dsa key. +# + + +# === +openssl_ocsp_tmout() { +( + if test -z "${SSH_OPENSLL_OCSP_TMOUT}"; then + sleep 1 + exit 0 + fi + + count=${SSH_OPENSLL_OCSP_TMOUT} + echo "OpenSSL OCSP responder socket timeout ${count}[sec.]" >&2 + while test ${count} -gt 0; do + printf 'O' + sleep 1 + count=`expr ${count} - 1` + done + printf 'X\n' +) +} + + +# === +killResponders() { +( + if test -z "${SSH_OPENSLL_OCSP_TMOUT}"; then + ( + has="" + for pidfile in va-*.pid; do + if test -r "${pidfile}"; then + kill `cat "${pidfile}"` > /dev/null 2>&1 + has="yes" + fi + done + if test -n "${has}"; then + openssl_ocsp_tmout + fi + ) + fi + ( + has="" + for pidfile in va-*.pid; do + if test -r "${pidfile}"; then + kill -9 `cat "${pidfile}"` > /dev/null 2>&1 + rm -f "${pidfile}" + has="yes" + fi + done + if test -n "${has}"; then + openssl_ocsp_tmout + fi + ) + : +) +} + + +# === +OCSPtestBREAK() { + echo + killResponders + testBREAK +} + +trap OCSPtestBREAK INT QUIT ABRT KILL TERM || exit 1 + + +# === +#args: +# $1 - port +#env. vars: +# OCSP_RESPKEY +# type +runResponder() { +( + port=$1 + + pidfile="va-${port}.pid" + test -r "${pidfile}" && exit 1 + + printf ' %s' "starting OCSP ${extd}responder${norm}(${attn}${type}${norm}) on ${attn}${SSHD_LISTENADDRESS}:${port}${norm}" + ( + ${OPENSSL} ocsp \ + -CA "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" \ + -rsigner "${OCSP_RESPKEY}-${type}.crt" \ + -rkey "${OCSP_RESPKEY}" \ + -index "${SSH_CAROOT}/index-${type}.txt" \ + -host ${SSHD_LISTENADDRESS} \ + -port ${port} 2> va-${type}.log & + pid=$! + echo ${pid} > "${pidfile}" + wait ${pid} + rm -f "${pidfile}" + ) 2> /dev/null & + + sleep 1 + test -r "${pidfile}"; show_status $? +) +} + + +# === +test_ocsp_cert () { +( + printSeparator + echo "Begin test ${extd}against${norm} OCSP provider from ${attn}certificate${norm} ..." + + retval=1 + for OCSP_RESPKEY in ${TEST_OCSP_RESPKEYS}; do + printSeparator + echo " respoder key base ${attn}${OCSP_RESPKEY}${norm} ..." + + creTestSSHDcfgFile + cat >> "$SSHD_CFG" <> "$SSHD_CFG" < "${SSH_CLIENTKEY}" && + chmod 600 "${SSH_CLIENTKEY}" && + "$TEST_SSH_SSHKEYGEN" -f "${SSH_CLIENTKEY}" -p -P "${KEY_PASS}" -N "" \ + > /dev/null && + "$TEST_SSH_SSHKEYGEN" -f "${SSH_CLIENTKEY}" -y \ + > "${SSH_CLIENTKEY}.pub" && + + for type in ${SSH_SIGN_TYPES}; do + case $keytype in + rsa) + case $type in + *dsa*) continue;; + esac + ;; + dsa) + case $type in + *rsa*) continue;; + esac + ;; + esac + + identity_file="${SSH_CLIENTKEY}-${type}" + ( cat "${SSH_CLIENTKEY}" + $OPENSSL x509 -in "${SSH_CACERTDIR}/${CAKEY_PREFIX}-${type}.crt.pem" \ + -subject -issuer -alias + ) > "${identity_file}" && + chmod 600 "${identity_file}" || return $? + done + done +} + +# === +#args: +# $1 - request to fail flag for blob +# $2 - request to fail flag for DN +test_self() { + + case $1 in + Y|y|Yes|yes|YES|1) + blob_msg="${warn}blob${norm}";; + *) + blob_msg="${extd}blob${norm}";; + esac + case $2 in + Y|y|Yes|yes|YES|1) + dn_msg="${warn}DN${norm}";; + *) + dn_msg="${extd}DN${norm}";; + esac + + for keytype in rsa dsa; do + SSH_CLIENTKEY="selfid_${keytype}" + + for type in ${SSH_SIGN_TYPES}; do + case $keytype in + rsa) + case $type in + *dsa*) continue;; + esac + ;; + dsa) + case $type in + *rsa*) continue;; + esac + ;; + esac + + identity_file="${SSH_CLIENTKEY}-${type}" + + cat "${SSH_CLIENTKEY}.pub" > "${AUTHORIZEDKEYSFILE}" && + runTest "" "${identity_file}" \ + "${type} ${blob_msg}" "$1" \ + || return $? + + sshkeytype=`getSSHkeyType "${identity_file}"` || return $? + subject=`getSubject "${identity_file}"` || return $? + + echo "${sshkeytype} Subject: ${subject}" > "${AUTHORIZEDKEYSFILE}" && + runTest "" "${identity_file}" \ + "${type} ${dn_msg}" "$2" \ + || return $? + done + done +} + +# === + +test_store () { + retval=0 + echo " - ${attn}with${norm} self-issued trusted by ${extd}x509store${norm}:" + printSeparator + + creTestSSHDcfgFile + cat >> "$SSHD_CFG" <> "$SSHD_CFG" <> "$SSHD_CFG" < + + +/* ================================================================== */ +/* ERRORS */ +#ifndef OPENSSL_NO_ERR +static ERR_STRING_DATA X509byLDAP_str_functs[] = { + { ERR_PACK(0, X509byLDAP_F_LOOKUPCRTL, 0) , "LOOKUPCRTL" }, + { ERR_PACK(0, X509byLDAP_F_LDAPHOST_NEW, 0) , "LDAPHOST_NEW" }, + { ERR_PACK(0, X509byLDAP_F_SET_PROTOCOL, 0) , "SET_PROTOCOL" }, + { ERR_PACK(0, X509byLDAP_F_RESULT2STORE, 0) , "RESULT2STORE" }, + { ERR_PACK(0, X509byLDAP_F_GET_BY_SUBJECT, 0) , "GET_BY_SUBJECT" }, + { 0, NULL } +}; + + +static ERR_STRING_DATA X509byLDAP_str_reasons[] = { + { X509byLDAP_R_INVALID_CRTLCMD , "invalid control command" }, + { X509byLDAP_R_NOT_LDAP_URL , "not ldap url" }, + { X509byLDAP_R_INVALID_URL , "invalid ldap url" }, + { X509byLDAP_R_INITIALIZATION_ERROR , "ldap initialization error" }, + { X509byLDAP_R_UNABLE_TO_GET_PROTOCOL_VERSION , "unable to get ldap protocol version" }, + { X509byLDAP_R_UNABLE_TO_SET_PROTOCOL_VERSION , "unable to set ldap protocol version" }, + { X509byLDAP_R_UNABLE_TO_COUNT_ENTRIES , "unable to count ldap entries" }, + { X509byLDAP_R_WRONG_LOOKUP_TYPE , "wrong lookup type" }, + { X509byLDAP_R_UNABLE_TO_GET_FILTER , "unable to get ldap filter" }, + { X509byLDAP_R_UNABLE_TO_BIND , "unable to bind to ldap server" }, + { X509byLDAP_R_SEARCH_FAIL , "search failure" }, + { 0, NULL } +}; +#endif /*ndef OPENSSL_NO_ERR*/ + + +void +ERR_load_X509byLDAP_strings(void) { + static int init = 1; + + if (init) { + init = 0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(ERR_LIB_X509byLDAP, X509byLDAP_str_functs); + ERR_load_strings(ERR_LIB_X509byLDAP, X509byLDAP_str_reasons); +#endif + } +} + + +static char* +ldap_errormsg(char *buf, size_t len, int err) { + snprintf(buf, len, "ldaperror=0x%x(%.256s)", err, ldap_err2string(err)); + return(buf); +} + + +static void +openssl_add_ldap_error(int err) { + char buf[512]; + ERR_add_error_data(1, ldap_errormsg(buf, sizeof(buf), err)); +} + + + +/* ================================================================== */ +/* LOOKUP by LDAP */ + +static const char ATTR_CACERT[] = "cACertificate"; +static const char ATTR_CACRL[] = "certificateRevocationList"; + +typedef struct ldaphost_s ldaphost; +struct ldaphost_s { + char *url; + char *binddn; + char *bindpw; + LDAPURLDesc *ldapurl; + LDAP *ld; + ldaphost *next; +}; + + +static ldaphost* ldaphost_new(const char *url); +static void ldaphost_free(ldaphost *p); + + +static int ldaplookup_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **ret); +static int ldaplookup_new(X509_LOOKUP *ctx); +static void ldaplookup_free(X509_LOOKUP *ctx); +static int ldaplookup_init(X509_LOOKUP *ctx); +static int ldaplookup_shutdown(X509_LOOKUP *ctx); +static int ldaplookup_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *ret); + +static int ldaplookup_add_search(X509_LOOKUP *ctx, const char *url); +static int ldaplookup_set_protocol(X509_LOOKUP *ctx, const char *ver); + + +X509_LOOKUP_METHOD x509_ldap_lookup = { + "Load certs and crls from LDAP server", + ldaplookup_new, /* new */ + ldaplookup_free, /* free */ + ldaplookup_init, /* init */ + ldaplookup_shutdown, /* shutdown */ + ldaplookup_ctrl, /* ctrl */ + ldaplookup_by_subject, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ +}; + + +X509_LOOKUP_METHOD* +X509_LOOKUP_ldap(void) { + return(&x509_ldap_lookup); +} + + +static int +ldaplookup_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, char **retp) { + int ret = 0; + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_ctrl: cmd=%d, argc=%s\n", cmd, argc); +#endif + switch (cmd) { + case X509_L_LDAP_HOST: + ret = ldaplookup_add_search(ctx, argc); + break; + case X509_L_LDAP_VERSION: + ret = ldaplookup_set_protocol(ctx, argc); + break; + default: + X509byLDAPerr(X509byLDAP_F_LOOKUPCRTL, X509byLDAP_R_INVALID_CRTLCMD); + break; + } + return(ret); +} + + +static int +ldaplookup_new(X509_LOOKUP *ctx) { +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_new:\n"); +#endif + if (ctx == NULL) + return(0); + + ctx->method_data = NULL; + return(1); +} + + +static void +ldaplookup_free(X509_LOOKUP *ctx) { + ldaphost *p; +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_free:\n"); +#endif + + if (ctx == NULL) + return; + + p = (ldaphost*) ctx->method_data; + while (p != NULL) { + ldaphost *q = p; + p = p->next; + ldaphost_free(q); + } +} + + +static int +ldaplookup_init(X509_LOOKUP *ctx) { +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_init:\n"); +#endif + return(1); +} + + +static int +ldaplookup_shutdown(X509_LOOKUP *ctx) { +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_shutdown:\n"); +#endif + return(1); +} + + +static ldaphost* +ldaphost_new(const char *url) { + ldaphost *p; + int ret; + + p = OPENSSL_malloc(sizeof(ldaphost)); + if (p == NULL) return(NULL); + + memset(p, 0, sizeof(ldaphost)); + + p->url = OPENSSL_malloc(strlen(url) + 1); + if (p->url == NULL) goto error; + strcpy(p->url, url); + + /*ldap://hostport/dn[?attrs[?scope[?filter[?exts]]]] */ + ret = ldap_is_ldap_url(url); + if (ret < 0) { + X509byLDAPerr(X509byLDAP_F_LDAPHOST_NEW, X509byLDAP_R_NOT_LDAP_URL); + goto error; + } + + ret = ldap_url_parse(url, &p->ldapurl); + if (ret != 0) { + X509byLDAPerr(X509byLDAP_F_LDAPHOST_NEW, X509byLDAP_R_INVALID_URL); + openssl_add_ldap_error(ret); + goto error; + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaphost_new: ldap_url_desc2str=%s\n", ldap_url_desc2str(p->ldapurl)); +fprintf(stderr, "TRACE_BY_LDAP ldaphost_new: ldapurl->%s://%s:%d\n", p->ldapurl->lud_scheme, p->ldapurl->lud_host, p->ldapurl->lud_port); +#endif + + /* open ldap connection */ + p->ld = ldap_init(p->ldapurl->lud_host, p->ldapurl->lud_port); + if(p->ld == NULL) { + X509byLDAPerr(X509byLDAP_F_LDAPHOST_NEW, X509byLDAP_R_INITIALIZATION_ERROR); + goto error; + } + + { + int version = -1; + + ret = ldap_get_option(p->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + if (ret != LDAP_OPT_SUCCESS) { + X509byLDAPerr(X509byLDAP_F_LDAPHOST_NEW, X509byLDAP_R_UNABLE_TO_GET_PROTOCOL_VERSION ); + goto error; + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaphost_new: using ldap v%d protocol\n", version); +#endif + } + + return(p); +error: + ldaphost_free(p); + return(NULL); +} + + +static void +ldaphost_free(ldaphost *p) { +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaphost_free:\n"); +#endif + if (p == NULL) return; + if (p->url != NULL) OPENSSL_free(p->url); + if (p->binddn != NULL) OPENSSL_free(p->binddn); + if (p->bindpw != NULL) OPENSSL_free(p->bindpw); + if (p->ldapurl != NULL) { + ldap_free_urldesc(p->ldapurl); + p->ldapurl = NULL; + } + if (p->ld != NULL) { + /* how to free ld ???*/ + p->ld = NULL; + } + OPENSSL_free(p); +} + + +static int/*bool*/ +ldaplookup_add_search(X509_LOOKUP *ctx, const char *url) { + ldaphost *p, *q; + + if (ctx == NULL) return(0); + if (url == NULL) return(0); + + q = ldaphost_new(url); + if (q == NULL) return(0); + + p = (ldaphost*) ctx->method_data; + if (p == NULL) { + ctx->method_data = (void*) q; + return(1); + } + + for(; p->next != NULL; p = p->next) { + /*find list end*/ + } + p->next = q; + + return(1); +} + + +static int/*bool*/ +ldaplookup_set_protocol(X509_LOOKUP *ctx, const char *ver) { + ldaphost *p; + char *q = NULL; + int n; + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_set_protocol(..., %s)\n", ver); +#endif + if (ctx == NULL) return(0); + if (ver == NULL) return(0); + + p = (ldaphost*) ctx->method_data; + if (p == NULL) return(0); + + n = (int) strtol(ver, &q, 10); + if (*q != '\0') return(0); + if ((n < LDAP_VERSION_MIN) || (n > LDAP_VERSION_MAX)) return(0); + + for(; p->next != NULL; p = p->next) { + /*find list end*/ + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_set_protocol(...): ver=%d\n", n); +#endif + { + int ret; + const int version = n; + + ret = ldap_set_option(p->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + if (ret != LDAP_OPT_SUCCESS) { + X509byLDAPerr(X509byLDAP_F_SET_PROTOCOL, X509byLDAP_R_UNABLE_TO_SET_PROTOCOL_VERSION); + openssl_add_ldap_error(ret); + return(0); + } + } + + return(1); +} + + +static char* +ldaplookup_filter(X509_NAME *name, const char *attribute) { + char *p = NULL; + int k; + BIO *mbio; + + mbio = BIO_new(BIO_s_mem()); + if (mbio == NULL) return(NULL); + + BIO_puts(mbio, "(&"); + + k = sk_X509_NAME_ENTRY_num(name->entries); + for (--k; k >= 0; k--) { + X509_NAME_ENTRY *ne; + ASN1_STRING *nv; + int nid; + + ne = sk_X509_NAME_ENTRY_value(name->entries, k); + nid = OBJ_obj2nid(ne->object); + + if ( + (nid != NID_organizationName) && + (nid != NID_organizationalUnitName) && + (nid != NID_commonName) + ) continue; + + BIO_puts(mbio, "("); + BIO_puts(mbio, OBJ_nid2sn(nid)); + BIO_puts(mbio, "="); + nv = ne->value; + /* + TODO: + we must escape '(' and ')' symbols and might to check for other symbols (>=128?) + BIO_puts(mbio, M_ASN1_STRING_data(nv)); + */ + { /* escape '(' and ')' */ + p = (char*)M_ASN1_STRING_data(nv); + for (; *p; p++) { + if ((*p == '(') || (*p == ')')) + BIO_write(mbio, "\\", 1); + BIO_write(mbio, p, 1); + } + } + BIO_puts(mbio, ")"); + } + + BIO_puts(mbio, "("); + BIO_puts(mbio, attribute); + BIO_puts(mbio, "=*)"); + + BIO_puts(mbio, ")"); + BIO_flush(mbio); + + k = BIO_pending(mbio); + p = OPENSSL_malloc(k + 1); + if (p == NULL) goto done; + + k = BIO_read(mbio, p, k); + p[k] = '\0'; + +done: + BIO_free_all(mbio); + return(p); +} + + +static int/*bool*/ +ldaplookup_check_attr( + int type, + const char *attr +) { + if (type == X509_LU_X509) + return(strncmp(attr, ATTR_CACERT, sizeof(ATTR_CACERT)) != 0); + + if (type == X509_LU_CRL) + return(strncmp(attr, ATTR_CACRL, sizeof(ATTR_CACRL)) != 0); + + return(0); +} + + +/* + * We will put into store X509 object from passed data in buffer only + * when object name match passed. To compare both names we use our + * method "ssh_X509_NAME_cmp"(it is more general). + */ +static int/*bool*/ +ldaplookup_data2store( + int type, + X509_NAME* name, + void* buf, + int len, + X509_STORE* store +) { + int ok = 0; + BIO *mbio; + + if (name == NULL) return(0); + if (buf == NULL) return(0); + if (len <= 0) return(0); + if (store == NULL) return(0); + + mbio = BIO_new_mem_buf(buf, len); + if (mbio == NULL) return(0); + + switch (type) { + case X509_LU_X509: { + X509 *x509 = d2i_X509_bio(mbio, NULL); + if(x509 == NULL) goto exit; + + /*This is correct since lookup method is by subject*/ + if (ssh_X509_NAME_cmp(name, X509_get_subject_name(x509)) != 0) goto exit; + + ok = X509_STORE_add_cert(store, x509); + } break; + case X509_LU_CRL: { + X509_CRL *crl = d2i_X509_CRL_bio(mbio, NULL); + if(crl == NULL) goto exit; + + if (ssh_X509_NAME_cmp(name, X509_CRL_get_issuer(crl)) != 0) goto exit; + + ok = X509_STORE_add_crl(store, crl); + } break; + } + +exit: + if (mbio != NULL) BIO_free_all(mbio); +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_data2store: ok=%d\n", ok); +#endif + return(ok); +} + + +static int +ldaplookup_result2store( + int type, + X509_NAME* name, + LDAP* ld, + LDAPMessage* res, + X509_STORE* store +) { + int count = 0; + int result; + LDAPMessage *entry; + + result = ldap_count_entries(ld, res); + if (result < 0) { + result = ldap_result2error(ld, res, 0); + X509byLDAPerr(X509byLDAP_F_RESULT2STORE, X509byLDAP_R_UNABLE_TO_COUNT_ENTRIES); + openssl_add_ldap_error(result); + goto done; + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_result2store: ldap_count_entries=%d\n", result); +#endif + + for(entry = ldap_first_entry(ld, res); + entry != NULL; + entry = ldap_next_entry(ld, entry) + ) { + char *attr; + BerElement *ber; +#ifdef TRACE_BY_LDAP +{ +char *dn = ldap_get_dn(ld, entry); +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_result2store(): ldap_get_dn=%s\n", dn); +ldap_memfree(dn); +} +#endif + for(attr = ldap_first_attribute(ld, entry, &ber); + attr != NULL; + attr = ldap_next_attribute(ld, entry, ber) + ) { + struct berval **vals; + struct berval **p; + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_result2store: attr=%s\n", attr); +#endif + if (!ldaplookup_check_attr(type, attr)) continue; + + vals = ldap_get_values_len(ld, entry, attr); + if (vals == NULL) continue; + + for(p = vals; *p; p++) { + struct berval *q = *p; + if (ldaplookup_data2store(type, name, q->bv_val, q->bv_len, store)) { + count++; + } + } + ldap_value_free_len(vals); + } + ber_free(ber, 0); + } +done: +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_result2store: count=%d\n", count); +#endif + return(count); +} + + +static int +ldaplookup_by_subject( + X509_LOOKUP *ctx, + int type, + X509_NAME *name, + X509_OBJECT *ret +) { + int count = 0; + ldaphost *lh; + const char *attrs[2]; + char *filter = NULL; + + + if (ctx == NULL) return(0); + if (name == NULL) return(0); + + lh = (ldaphost*) ctx->method_data; + if (lh == NULL) return(0); + + switch(type) { + case X509_LU_X509: { + attrs[0] = ATTR_CACERT; + } break; + case X509_LU_CRL: { + attrs[0] = ATTR_CACRL; + } break; + default: { + X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_WRONG_LOOKUP_TYPE); + goto done; + } + } + attrs[1] = NULL; + + filter = ldaplookup_filter(name, attrs[0]); + if (filter == NULL) { + X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_GET_FILTER); + goto done; + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: filter=%s\n", filter); +#endif + + for (; lh != NULL; lh = lh->next) { + LDAPMessage *res = NULL; + int result; + +#ifdef TRACE_BY_LDAP +{ +int version = -1; + +ldap_get_option(lh->ld, LDAP_OPT_PROTOCOL_VERSION, &version); +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject:" +" bind to \"%s://%s:%d\"" +" using ldap v%d protocol\n" +, lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port +, version +); +} +#endif + + /* anonymous bind - data must be retrieved by anybody */ + result = ldap_simple_bind_s(lh->ld, NULL/*binddn*/, NULL/*bindpw*/); + if (result != LDAP_SUCCESS) { + X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_UNABLE_TO_BIND); + { + char buf[1024]; + snprintf(buf, sizeof(buf), + " url=\"%s://%s:%d\"" + " ldaperror=0x%x(%.256s)" + , lh->ldapurl->lud_scheme, lh->ldapurl->lud_host, lh->ldapurl->lud_port + , result, ldap_err2string(result) + ); + ERR_add_error_data(1, buf); + } + continue; + } + + result = ldap_search_s(lh->ld, lh->ldapurl->lud_dn, LDAP_SCOPE_SUBTREE, filter, (char**)attrs, 0, &res); +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject:" +" ldap_search_s return 0x%x(%s)\n" +, result, ldap_err2string(result)); +#endif + + if (result != LDAP_SUCCESS) { + X509byLDAPerr(X509byLDAP_F_GET_BY_SUBJECT, X509byLDAP_R_SEARCH_FAIL); + ldap_msgfree(res); + continue; + } + + result = ldaplookup_result2store(type, name, lh->ld, res, ctx->store_ctx); + if (result > 0) count += result; + + ldap_msgfree(res); + + /*do not call ldap_unbind_s*/ + } + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: count=%d\n", count); +#endif + if (count > 0) { + /* + * we have added at least one to the cache so now pull one out again + */ + union { + struct { + X509_CINF st_x509_cinf; + X509 st_x509; + } x509; + struct { + X509_CRL_INFO st_crl_info; + X509_CRL st_crl; + } crl; + } data; + + X509_OBJECT stmp, *tmp; + int k; + + memset(&data, 0, sizeof(data)); + stmp.type = type; + switch(type) { + case X509_LU_X509: { + data.x509.st_x509_cinf.subject = name; + data.x509.st_x509.cert_info = &data.x509.st_x509_cinf; + stmp.data.x509 = &data.x509.st_x509; + } break; + case X509_LU_CRL: { + data.crl.st_crl_info.issuer = name; + data.crl.st_crl.crl = &data.crl.st_crl_info; + stmp.data.crl = &data.crl.st_crl; + } break; + default: + count = 0; + goto done; + } + + CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE); + k = sk_X509_OBJECT_find(ctx->store_ctx->objs, &stmp); + if (k >= 0) + tmp = sk_X509_OBJECT_value(ctx->store_ctx->objs, k); + else + tmp = NULL; + CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE); +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_by_subject: k=%d, tmp=%p\n", k, tmp); +#endif + + if (tmp == NULL) { + count = 0; + goto done; + } + + ret->type = tmp->type; + memcpy(&ret->data, &tmp->data, sizeof(ret->data)); + } + +done: + if (filter != NULL) OPENSSL_free(filter); + return(count > 0); +} diff -ruN openssh-4.2p1/x509_by_ldap.h openssh-4.2p1+x509-5.5/x509_by_ldap.h --- openssh-4.2p1/x509_by_ldap.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/x509_by_ldap.h 2004-11-19 09:06:00.000000000 +0200 @@ -0,0 +1,98 @@ +#ifndef X509_BY_LDAP_H +#define X509_BY_LDAP_H +/* + * Copyright (c) 2004 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. + */ + +/* openssh specific includes */ +#include "includes.h" +#ifndef LDAP_ENABLED +# include "error: LDAP is disabled" +#endif + +/* required includes */ +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +X509_LOOKUP_METHOD* X509_LOOKUP_ldap(void); + +#define X509_L_LDAP_HOST 1 +#define X509_L_LDAP_VERSION 2 + +#define X509_LOOKUP_add_ldap(x,value) \ + X509_LOOKUP_ctrl((x),X509_L_LDAP_HOST,(value),(long)(0),NULL) +#define X509_LOOKUP_set_protocol(x,value) \ + X509_LOOKUP_ctrl((x),X509_L_LDAP_VERSION,(value),(long)(0),NULL) + + +/* Error codes for the X509byLDAP functions. */ +#ifdef NO_ERR /* openssl < 0.7.x */ +# define OPENSSL_NO_ERR /* openssl >= 0.7.x */ +#endif + +#ifndef OPENSSL_NO_ERR + +void ERR_load_X509byLDAP_strings(void); + +/* library */ +#define ERR_LIB_X509byLDAP ERR_LIB_USER + +#define X509byLDAPerr(f,r) ERR_PUT_error(ERR_LIB_X509byLDAP,(f),(r),__FILE__,__LINE__) + +/* BEGIN ERROR CODES */ + +/* Function codes. */ +#define X509byLDAP_F_LOOKUPCRTL 100 +#define X509byLDAP_F_LDAPHOST_NEW 101 +#define X509byLDAP_F_SET_PROTOCOL 102 +#define X509byLDAP_F_RESULT2STORE 103 +#define X509byLDAP_F_GET_BY_SUBJECT 104 + +/* Reason codes. */ +#define X509byLDAP_R_INVALID_CRTLCMD 100 +#define X509byLDAP_R_NOT_LDAP_URL 101 +#define X509byLDAP_R_INVALID_URL 102 +#define X509byLDAP_R_INITIALIZATION_ERROR 103 +#define X509byLDAP_R_UNABLE_TO_GET_PROTOCOL_VERSION 104 +#define X509byLDAP_R_UNABLE_TO_SET_PROTOCOL_VERSION 105 +#define X509byLDAP_R_UNABLE_TO_COUNT_ENTRIES 106 +#define X509byLDAP_R_WRONG_LOOKUP_TYPE 107 +#define X509byLDAP_R_UNABLE_TO_GET_FILTER 108 +#define X509byLDAP_R_UNABLE_TO_BIND 109 +#define X509byLDAP_R_SEARCH_FAIL 110 + +#endif /*ndef OPENSSL_NO_ERR*/ + + +#ifdef __cplusplus +} +#endif + + +#endif /*ndef X509_BY_LDAP_H*/ diff -ruN openssh-4.2p1/x509_nm_cmp.c openssh-4.2p1+x509-5.5/x509_nm_cmp.c --- openssh-4.2p1/x509_nm_cmp.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/x509_nm_cmp.c 2005-08-05 23:30:30.000000000 +0300 @@ -0,0 +1,290 @@ +/* + * 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: + * 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. + */ + +/* initial code is moved from ssh-x509.c */ +#include "includes.h" + +#ifndef SSH_X509STORE_DISABLED + +#include "x509store.h" +#include "log.h" + + +static int +ssh_ASN1_OBJECT_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { + int lmin = MIN(a->length, b->length); + + int ret = memcmp(a->data, b->data, lmin); + + return((ret == 0) + ? (b->length - a->length) + : ret); +} + + +static int +ssh_ASN1_STRING_casecmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + int la = M_ASN1_STRING_length(a); + int lb = M_ASN1_STRING_length(b); + const char *sa = (const char *)M_ASN1_STRING_data(a); + const char *sb = (const char *)M_ASN1_STRING_data(b); + + return((strncasecmp(sa, sb, MIN(la, lb)) != 0) ? (lb - la) : 0); +} + + +/* 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_printable_casecmp(const u_char *pa, int la, const u_char *pb, int lb) +{ +/* + * 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((int)*pa); la--, pa++); + for (; lb > 0 && isspace((int)*pb); lb--, pb++); + + /* skip trailing spaces */ + { + 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((int)*pa); + int chB = tolower((int)*pb); + + if (chA != chB) + return(chB - chA); + + pa++; pb++; + la--; lb--; + if (isspace(chA)) { + for (; la > 0 && isspace((int)*pa); la--, pa++); + for (; lb > 0 && isspace((int)*pb); lb--, pb++); + } + } + return(lb - la); +} + + +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); +} + + +/* + * 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" :-[ . + * 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. + * i.e. X509_NAME{"/C=XX/O=YY"} is not equal to X509_NAME{"/O=YY/C=XX"} + */ +int +ssh_X509_NAME_cmp(X509_NAME *_a, X509_NAME *_b) { + int k, n; + X509_NAME *b; + +#if 1 + /*XXX: to call fatal when _a or _b is NULL or to use next*/ + if (_a == NULL) { + return((_b == NULL) ? 0 : 1); + } else { + if (_b == NULL) return(-1); + } +#else + if (_a == NULL) { + fatal("ssh_X509_NAME_cmp: first name is NULL"); + } + if (_b == NULL) { + fatal("ssh_X509_NAME_cmp: second name is NULL"); + } +#endif + + k = sk_X509_NAME_ENTRY_num(_a->entries); + n = sk_X509_NAME_ENTRY_num(_b->entries); + + if (k != n) + return(n - k); + + b = X509_NAME_dup(_b); + n = 0; + for (--k; k >= 0; k--) { + X509_NAME_ENTRY *neA; + ASN1_STRING *nvA; + int nid; + X509_NAME_ENTRY *neB; + ASN1_STRING *nvB; + int loc; + + neA = sk_X509_NAME_ENTRY_value(_a->entries, k); + nvA = neA->value; + nid = OBJ_obj2nid(neA->object); + loc = X509_NAME_get_index_by_NID(b, nid, -1); + if (loc < 0) { + char buf1[X509_NAME_MAXLEN]; + char buf2[X509_NAME_MAXLEN]; + + X509_NAME_oneline(_a, buf1, sizeof(buf1)); + X509_NAME_oneline(_b, buf2, sizeof(buf2)); + debug3("ssh_X509_NAME_cmp: insufficient entries with nid=%d(%.40s) in second name." + " na=%.*s, nb=%.*s", + nid, OBJ_nid2ln(nid), + (int) sizeof(buf1), buf1, + (int) sizeof(buf1), buf2); + n = -1; + break; + } +trynextentry: + neB = sk_X509_NAME_ENTRY_value(b->entries, loc); + nvB = neB->value; +#ifdef SSHX509TEST_DBGCMP +{ + int l, tag; + + 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 + + if (nid == NID_pkcs9_emailAddress) { + int tag; + + tag = M_ASN1_STRING_type(nvA); + if (tag != V_ASN1_IA5STRING) { + /* to be strict and return nonzero or ... ? XXX + n = -1; + break; + */ + error("ssh_X509_NAME_cmp: incorrect type for emailAddress(a) %d(%.30s)", tag, ASN1_tag2str(tag)); + } + + tag = M_ASN1_STRING_type(nvB); + if (tag != V_ASN1_IA5STRING) { + /* to be strict and return nonzero or ... ? XXX + n = 1; + break; + */ + error("ssh_X509_NAME_cmp: incorrect type for emailAddress(b) %d(%.30s)", tag, ASN1_tag2str(tag)); + } + + n = ssh_ASN1_STRING_casecmp(nvA, nvB); + if (n == 0) goto entryisok; + + goto getnextentry; + } + if ((M_ASN1_STRING_type(nvA) == V_ASN1_PRINTABLESTRING) || + (M_ASN1_STRING_type(nvB) == V_ASN1_PRINTABLESTRING) ) { + n = ssh_ASN1_PRINTABLESTRING_cmp(nvA, nvB); + if (n == 0) goto entryisok; + + goto getnextentry; + } + + n = M_ASN1_STRING_length(nvA) - M_ASN1_STRING_length(nvB); + if (n != 0) goto getnextentry; + + n = M_ASN1_STRING_length(nvA); + n = memcmp(nvA->data, nvB->data, n); + if (n != 0) goto getnextentry; + + /* openssl check object too */ + n = ssh_ASN1_OBJECT_cmp(neA->object, neB->object); + if (n != 0) goto getnextentry; + +entryisok: + { + X509_NAME_ENTRY *ne = X509_NAME_delete_entry(b, loc); + X509_NAME_ENTRY_free(ne); + } + continue; +getnextentry: + loc = X509_NAME_get_index_by_NID(b, nid, loc); + if (loc < 0) { + break; + } + goto trynextentry; + } + + 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*/ diff -ruN openssh-4.2p1/x509store.c openssh-4.2p1+x509-5.5/x509store.c --- openssh-4.2p1/x509store.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/x509store.c 2006-04-25 22:08:39.000000000 +0300 @@ -0,0 +1,955 @@ +/* + * Copyright (c) 2002-2006 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 "x509store.h" +#include "openssl/x509v3.h" +#include "log.h" + +#ifndef SSH_X509STORE_DISABLED +#include "xmalloc.h" +#include "pathnames.h" +#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 +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +SSH_X509Flags +ssh_x509flags = { + 0, /* is_server */ + -1, /* allowedcertpurpose */ +#ifndef SSH_X509STORE_DISABLED + -1, /* key_allow_selfissued */ + -1 /* mandatory_crl */ +#endif /*ndef SSH_X509STORE_DISABLED*/ +}; + + +#ifndef SSH_X509STORE_DISABLED +static X509_STORE *x509store = NULL; +#if 1 +# define SSH_CHECK_REVOKED +#endif + + +#ifdef SSH_CHECK_REVOKED +static X509_STORE *x509revoked = NULL; +static int ssh_x509revoked_cb(int ok, X509_STORE_CTX *ctx); + + +static char * +ssh_ASN1_INTEGER_2_string(ASN1_INTEGER *_asni) { + BIO *bio; + int k; + char *p; + + if (_asni == NULL) { + error("ssh_ASN1_INTEGER_2_string: _asni is NULL"); + return(NULL); + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + fatal("ssh_ASN1_INTEGER_2_string: out of memory"); + return(NULL); /* ;-) */ + } + + i2a_ASN1_INTEGER(bio, _asni); + k = BIO_pending(bio); + p = xmalloc(k + 1); /*fatal on error*/ + k = BIO_read(bio, p, k); + p[k] = '\0'; + BIO_free_all(bio); + + return(p); +} +#endif /*def SSH_CHECK_REVOKED*/ + + +int +ssh_x509store_lookup(X509_STORE *store, int type, X509_NAME *name, X509_OBJECT *xobj) { + X509_STORE_CTX ctx; + int ret; + + X509_STORE_CTX_init(&ctx, store, NULL, NULL); + ret = X509_STORE_get_by_subject(&ctx, type, name, xobj); + X509_STORE_CTX_cleanup(&ctx); + + return(ret); +} + + +static int +ssh_x509store_cb(int ok, X509_STORE_CTX *ctx) { + if ((!ok) && + (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) + ) { + if (ssh_x509flags.key_allow_selfissued) + ok = ssh_is_selfsigned(ctx->cert); + } + if (!ok) { + char buf[X509_NAME_MAXLEN]; + X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf)); + error("ssh_x509store_cb: subject='%.*s', error %d at %d depth lookup:%.200s", + (int) sizeof(buf), buf, + ctx->error, + ctx->error_depth, + X509_verify_cert_error_string(ctx->error)); + +#if 0 + if (ctx->error == X509_V_ERR_CERT_HAS_EXPIRED) ok=1; + /* since we are just checking the certificates, it is + * ok if they are self signed. But we should still warn + * the user. + */ + if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1; + /* Continue after extension errors too */ + if (ctx->error == X509_V_ERR_INVALID_CA) ok=1; + if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1; + if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1; + if (ctx->error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) ok=1; +#endif + } +#ifdef SSH_CHECK_REVOKED + if (ok) { + ok = ssh_x509revoked_cb(ok, ctx); + } +#endif + return(ok); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +typedef struct { + const char **synonyms; +} CertPurposes; + + +static const char *__purpose_any[] = { + "any", "any purpose", "any_purpose", "anypurpose", NULL +}; + + +static const char *__purpose_sslclient[] = { + "sslclient", "ssl client", "ssl_client", "client", NULL +}; + + +static const char *__purpose_sslserver[] = { + "sslserver", "ssl server", "ssl_server", "server", NULL +}; + + +static CertPurposes +sslclient_purposes[] = { + { __purpose_sslclient }, + { __purpose_any }, + { NULL } +}; + + +static CertPurposes +sslserver_purposes [] = { + { __purpose_sslserver }, + { __purpose_any }, + { NULL } +}; + + +static const char* +get_cert_purpose(const char* _purpose_synonym, CertPurposes *_purposes) { + int i; + + for (i = 0; _purposes[i].synonyms; i++) { + const char *q = _purposes[i].synonyms[0]; + if (strcasecmp(_purpose_synonym, q) == 0 ) { + return(q); + } else { + const char **p; + for (p = (_purposes[i].synonyms) + 1; *p; p++) { + if (strcasecmp(_purpose_synonym, *p) == 0 ) { + return(q); + } + } + } + } + return(NULL); +} + + +void +ssh_x509flags_initialize(SSH_X509Flags *flags, int is_server) { + flags->is_server = is_server; + flags->allowedcertpurpose = -1; +#ifndef SSH_X509STORE_DISABLED + flags->key_allow_selfissued = -1; + flags->mandatory_crl = -1; +#endif /*ndef SSH_X509STORE_DISABLED*/ +} + + +void +ssh_x509flags_defaults(SSH_X509Flags *flags) { + if (flags->allowedcertpurpose == -1) { + int is_server = flags->is_server; + const char* purpose_synonym = is_server ? __purpose_sslclient[0] : __purpose_sslserver[0]; + + flags->allowedcertpurpose = ssh_get_x509purpose_s(is_server, purpose_synonym); + } +#ifndef SSH_X509STORE_DISABLED + if (flags->key_allow_selfissued == -1) { + flags->key_allow_selfissued = 0; + } +#ifdef SSH_CHECK_REVOKED + if (flags->mandatory_crl == -1) { + flags->mandatory_crl = 0; + } +#else + if (flags->mandatory_crl != -1) { + logit("useless option: mandatory_crl"); + } +#endif +#endif /*ndef SSH_X509STORE_DISABLED*/ +} + + +int +ssh_get_x509purpose_s(int _is_server, const char* _purpose_synonym) { + const char * sslpurpose; + + sslpurpose = get_cert_purpose(_purpose_synonym, + (_is_server ? sslclient_purposes : sslserver_purposes)); + if (sslpurpose != NULL) { + int purpose_index = X509_PURPOSE_get_by_sname((char*)sslpurpose); + if (purpose_index < 0) + fatal( "ssh_get_x509purpose_s(%.10s): " + "X509_PURPOSE_get_by_sname fail for argument '%.30s(%.40s)'", + (_is_server ? "server" : "client"), + sslpurpose, _purpose_synonym); + return(purpose_index); + } + return(-1); +} + + +#ifndef SSH_X509STORE_DISABLED +int/*bool*/ +ssh_is_selfsigned(X509 *_cert) { + char buf[X509_NAME_MAXLEN]; + X509_NAME *issuer, *subject; + + issuer = X509_get_issuer_name(_cert); + X509_NAME_oneline(issuer, buf, sizeof(buf)); + debug3("ssh_is_selfsigned: issuer='%.*s'", (int) sizeof(buf), buf); + + subject = X509_get_subject_name(_cert); + X509_NAME_oneline(subject, buf, sizeof(buf)); + debug3("ssh_is_selfsigned: subject='%.*s'", (int) sizeof(buf), buf); + + return (ssh_X509_NAME_cmp(issuer, subject) == 0); +} + + +void +ssh_x509store_initialize(X509StoreOptions *options) { + options->certificate_file = NULL; + options->certificate_path = NULL; + options->revocation_file = NULL; + options->revocation_path = NULL; +#ifdef LDAP_ENABLED + options->ldap_ver = NULL; + options->ldap_url = NULL; +#endif +} + + +void +ssh_x509store_system_defaults(X509StoreOptions *options) { + if (options->certificate_file == NULL) + options->certificate_file = _PATH_CA_CERTIFICATE_FILE; + if (options->certificate_path == NULL) + options->certificate_path = _PATH_CA_CERTIFICATE_PATH; + if (options->revocation_file == NULL) + options->revocation_file = _PATH_CA_REVOCATION_FILE; + if (options->revocation_path == NULL) + options->revocation_path = _PATH_CA_REVOCATION_PATH; +#ifdef LDAP_ENABLED + /*nothing to do ;-)*/ +#endif +} + + +static void +tilde_expand_filename2(const char **_fn, const char* _default, uid_t uid) { + if (*_fn == NULL) { + *_fn = tilde_expand_filename(_default, uid); + } else { + const char *p = *_fn; + *_fn = tilde_expand_filename(p, uid); + xfree((void*)p); + } +} + + +void +ssh_x509store_user_defaults(X509StoreOptions *options, uid_t uid) { + tilde_expand_filename2(&options->certificate_file, _PATH_USERCA_CERTIFICATE_FILE, uid); + tilde_expand_filename2(&options->certificate_path, _PATH_USERCA_CERTIFICATE_PATH, uid); + tilde_expand_filename2(&options->revocation_file , _PATH_USERCA_REVOCATION_FILE , uid); + tilde_expand_filename2(&options->revocation_path , _PATH_USERCA_REVOCATION_PATH , uid); +#ifdef LDAP_ENABLED + /*nothing to do ;-)*/ +#endif +} + + +static void +ssh_x509store_initcontext(void) { + if (x509store == NULL) { + x509store = X509_STORE_new(); + if (x509store == NULL) { + fatal("cannot create x509store context"); + } + X509_STORE_set_verify_cb_func(x509store, ssh_x509store_cb); + } +#ifdef SSH_CHECK_REVOKED + if (x509revoked == NULL) { + x509revoked = X509_STORE_new(); + if (x509revoked == NULL) { + fatal("cannot create x509revoked context"); + } + } +#endif +} + + +int/*bool*/ +ssh_x509store_addlocations(const X509StoreOptions *_locations) { + int flag; + + if (_locations == NULL) { + error("ssh_x509store_addlocations: _locations is NULL"); + return(0); + } + if ((_locations->certificate_path == NULL) && + (_locations->certificate_file == NULL)) { + error("ssh_x509store_addlocations: certificate path and file are NULLs"); + return(0); + } +#ifdef SSH_CHECK_REVOKED + if ((_locations->revocation_path == NULL) && + (_locations->revocation_file == NULL)) { + error("ssh_x509store_addlocations: revocation path and file are NULLs"); + return(0); + } +#endif + ssh_x509store_initcontext(); + + flag = 0; + /* + * Note: + * After X509_LOOKUP_{add_dir|load_file} calls we must call + * ERR_clear_error() otherwise when the first call to + * X509_LOOKUP_XXXX fail the second call fail too ! + */ + if (_locations->certificate_path != NULL) { + X509_LOOKUP *lookup = X509_STORE_add_lookup(x509store, X509_LOOKUP_hash_dir()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add hash dir lookup !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_add_dir(lookup, _locations->certificate_path, X509_FILETYPE_PEM)) { + debug2("hash dir '%.400s' added to x509 store", _locations->certificate_path); + flag = 1; + } + ERR_clear_error(); + } + if (_locations->certificate_file != NULL) { + X509_LOOKUP *lookup = X509_STORE_add_lookup(x509store, X509_LOOKUP_file()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add file lookup !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_load_file(lookup, _locations->certificate_file, X509_FILETYPE_PEM)) { + debug2("file '%.400s' added to x509 store", _locations->certificate_file); + flag = 1; + } + ERR_clear_error(); + } + /*at least one lookup should succeed*/ + if (flag == 0) return(0); + + flag = 0; +#ifdef SSH_CHECK_REVOKED + if (_locations->revocation_path != NULL) { + X509_LOOKUP *lookup = X509_STORE_add_lookup(x509revoked, X509_LOOKUP_hash_dir()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add hash dir revocation lookup !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_add_dir(lookup, _locations->revocation_path, X509_FILETYPE_PEM)) { + debug2("hash dir '%.400s' added to x509 revocation store", _locations->revocation_path); + flag = 1; + } + ERR_clear_error(); + } + if (_locations->revocation_file != NULL) { + X509_LOOKUP *lookup = X509_STORE_add_lookup(x509revoked, X509_LOOKUP_file()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add file revocation lookup !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_load_file(lookup, _locations->revocation_file, X509_FILETYPE_PEM)) { + debug2("file '%.400s' added to x509 revocation store", _locations->revocation_file); + flag = 1; + } + ERR_clear_error(); + } +#else /*ndef SSH_CHECK_REVOKED*/ + if (_locations->revocation_path != NULL) { + logit("useless option: revocation_path"); + } + if (_locations->revocation_file != NULL) { + logit("useless option: revocation_file"); + } + flag = 1; +#endif /*ndef SSH_CHECK_REVOKED*/ + /*at least one revocation lookup should succeed*/ + if (flag == 0) return(0); + +#ifdef LDAP_ENABLED + if (_locations->ldap_url != NULL) { + X509_LOOKUP *lookup; + + lookup = X509_STORE_add_lookup(x509store, X509_LOOKUP_ldap()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add ldap lookup !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_add_ldap(lookup, _locations->ldap_url)) { + debug2("ldap url '%.400s' added to x509 store", _locations->ldap_url); + } + if (_locations->ldap_ver != NULL) { + if (!X509_LOOKUP_set_protocol(lookup, _locations->ldap_ver)) { + fatal("ssh_x509store_addlocations: cannot set ldap version !"); + return(0); /* ;-) */ + } + } + /*ERR_clear_error();*/ + +#ifdef SSH_CHECK_REVOKED + lookup = X509_STORE_add_lookup(x509revoked, X509_LOOKUP_ldap()); + if (lookup == NULL) { + fatal("ssh_x509store_addlocations: cannot add ldap lookup(revoked) !"); + return(0); /* ;-) */ + } + if (X509_LOOKUP_add_ldap(lookup, _locations->ldap_url)) { + debug2("ldap url '%.400s' added to x509 store(revoked)", _locations->ldap_url); + } + if (_locations->ldap_ver != NULL) { + if (!X509_LOOKUP_set_protocol(lookup, _locations->ldap_ver)) { + fatal("ssh_x509store_addlocations: cannot set ldap version(revoked) !"); + return(0); /* ;-) */ + } + } + /*ERR_clear_error();*/ +#endif /*def SSH_CHECK_REVOKED*/ + } +#endif /*def LDAP_ENABLED*/ + + return(1); +} + + +static int +ssh_verify_cert(X509_STORE_CTX *_csc, X509 *_cert) { + X509_STORE_CTX_init(_csc, x509store, _cert, NULL); + + if (ssh_x509flags.allowedcertpurpose >= 0) { + int def_purpose = ( ssh_x509flags.is_server + ? X509_PURPOSE_SSL_CLIENT + : X509_PURPOSE_SSL_SERVER + ); + X509_PURPOSE *xptmp = X509_PURPOSE_get0(ssh_x509flags.allowedcertpurpose); + int purpose, flag; + if (xptmp == NULL) { + fatal("ssh_verify_cert: cannot get purpose from index"); + return(-1); /* ;-) */ + } + purpose = X509_PURPOSE_get_id(xptmp); + flag = X509_STORE_CTX_purpose_inherit(_csc, def_purpose, purpose, 0); + if (flag <= 0) { + /* + * By default openssl applications don't check return code from + * X509_STORE_CTX_set_purpose or X509_STORE_CTX_purpose_inherit. + * + * Both methods return 0 (zero) and don't change purpose in context when: + * -X509_STORE_CTX_set_purpose(...) + * purpose is X509_PURPOSE_ANY + * -X509_STORE_CTX_purpose_inherit(...) + * purpose is X509_PURPOSE_ANY and default purpose is zero (!) + * + * Take note when purpose is "any" check method in current + * OpenSSL code just return 1. This openssl behavior is same + * as ssh option "AllowedCertPurpose=skip". + */ + int ecode; + char ebuf[256]; + + ecode = X509_STORE_CTX_get_error(_csc); + error("ssh_verify_cert: context purpose error, code=%d, msg='%.200s'" + , ecode + , X509_verify_cert_error_string(ecode)); + + ecode = ERR_get_error(); + ERR_error_string_n(ecode, ebuf, sizeof(ebuf)); + error("ssh_verify_cert: X509_STORE_CTX_purpose_inherit failed with '%.256s'" + , ebuf); + + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + return(-1); + } + } + + /* + if (issuer_checks) + X509_STORE_CTX_set_flags(_csc, X509_V_FLAG_CB_ISSUER_CHECK); + */ + + if (X509_verify_cert(_csc) == 0) { + int ecode = X509_STORE_CTX_get_error(_csc); + error("ssh_verify_cert: verify error, code=%d, msg='%.200s'" + , ecode + , X509_verify_cert_error_string(ecode)); + return(-1); + } + + return(1); +} +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +int +ssh_x509cert_check(X509 *_cert) { + int ret = 1; +#ifndef SSH_X509STORE_DISABLED + X509_STORE_CTX *csc; +#else /*def SSH_X509STORE_DISABLED*/ + X509_PURPOSE *xptmp; +#endif /*def SSH_X509STORE_DISABLED*/ + +#ifndef SSH_X509STORE_DISABLED + if (x509store == NULL) { + error("ssh_x509cert_check: context is NULL"); + return(-1); + } + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char buf[X509_NAME_MAXLEN]; + X509_NAME_oneline( X509_get_subject_name(_cert), buf, sizeof(buf)); + debug3("ssh_x509cert_check: for '%.*s'", (int) sizeof(buf), buf); + } + + csc = X509_STORE_CTX_new(); + if (csc == NULL) { + int ecode = ERR_get_error(); + char ebuf[256]; + ERR_error_string_n(ecode, ebuf, sizeof(ebuf)); + error("ssh_x509cert_check: X509_STORE_CTX_new failed with '%.256s'", ebuf); + + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + return(-1); + } + + ret = ssh_verify_cert(csc, _cert); + X509_STORE_CTX_free(csc); +#ifdef SSH_OCSP_ENABLED + if (ret > 0) { +/* + * OpenSSH implementation first verify and validate certificate by + * "X.509 store" with certs and crls from file system. It is fast + * check. After this when certificate chain is correct and + * certificate is not revoked we send a status request to an OCSP + * responder if configured. + * + * RFC2560(OCSP): + * ... + * 2.7 CA Key Compromise + * If an OCSP responder knows that a particular CA's private key + * has been compromised, it MAY return the revoked state for all + * certificates issued by that CA. + * ... + * 5. Security Considerations + * For this service to be effective, certificate using systems must + * connect to the certificate status service provider. In the event + * such a connection cannot be obtained, certificate-using systems + * could implement CRL processing logic as a fall-back position. + * ... + * RFC2560(OCSP)^ + * + * About OpenSSH implementation: + * 1.) We preffer to delegate validation of issuer certificates to + * 'OCSP Provider'. It is easy and simple to configure an OCSP + * responder to return revoked state for all certificates issued + * by a CA. Usually 'OCSP Provider' admins shall be first informed + * for certificates with changed state. In each case this simplify + * 'OCSP client'. + * 2.) To conform to RFC2560 we should use OCSP to check status of + * all certificates in the chain. Since this is network request it + * is good to implement a cache and to save status with lifetime. + * Might is good to have an OCSP cache server ;-). + * + * To minimize network latency and keeping in mind 1.) we send + * 'OCSP request' only for the last certificate in the chain, i.e. + * sended client or server certificate. + * + * Therefore instead to send OCSP request in ssh_x509revoked_cb() + * we do this here. + */ + ret = ssh_ocsp_validate(_cert, x509store); + } +#endif /*def SSH_OCSP_ENABLED*/ + +#else /*def SSH_X509STORE_DISABLED*/ + if (ssh_x509flags.allowedcertpurpose >= 0) { + xptmp = X509_PURPOSE_get0(ssh_x509flags.allowedcertpurpose); + if (xptmp == NULL) { + fatal("ssh_x509cert_check: cannot get purpose from index"); + return(-1); /* ;-) */ + } + ret = X509_check_purpose(_cert, X509_PURPOSE_get_id(xptmp), 0); + if (ret < 0) { + logit("ssh_x509cert_check: X509_check_purpose return %d", ret); + ret = 0; + } + } +#endif /*def SSH_X509STORE_DISABLED*/ + debug3("ssh_x509cert_check: return %d", ret); + return(ret); +} + + +#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"); + return(0); + } + if (_crl == NULL) { + debug("ssh_check_crl: crl is NULL"); + return(1); + } + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + BIO *bio; + char *p; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + fatal("ssh_check_crl: out of memory"); + return(0); /* ;-) */ + } + + X509_NAME_oneline(X509_CRL_get_issuer(_crl), buf, sizeof(buf)); + + BIO_printf(bio, ", Last Update: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(_crl)); + + BIO_printf(bio, ", Next Update: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(_crl)); + + k = BIO_pending(bio); + p = xmalloc(k + 1); /*fatal on error*/ + k = BIO_read(bio, p, k); + p[k] = '\0'; + + debug3("ssh_check_crl: Issuer: %s%s", buf, p); + + xfree(p); + BIO_free(bio); + } + +/* RFC 3280: + * The cRLSign bit is asserted when the subject public key is used + * for verifying a signature on certificate revocation list (e.g., a + * CRL, delta CRL, or an ARL). This bit MUST be asserted in + * certificates that are used to verify signatures on CRLs. + */ + if (/*???(_issuer->ex_flags & EXFLAG_KUSAGE) &&*/ + !(_issuer->ex_kusage & KU_CRL_SIGN) + ) { + 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); + #endif + return(0); + } + + { + EVP_PKEY *pkey = X509_get_pubkey(_issuer); + if (pkey == NULL) { + error("ssh_check_crl: unable to decode issuer public key"); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); + return(0); + } + + if (X509_CRL_verify(_crl, pkey) <= 0) { + 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); + } + EVP_PKEY_free(pkey); + } + + + 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); + 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); + return(0); + } + + k = X509_cmp_time(X509_CRL_get_nextUpdate(_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 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) { + 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); + } + + return(1); +} + + +static int/*bool*/ +ssh_is_cert_revoked(X509_STORE_CTX *_ctx, X509_CRL *_crl, X509 *_cert) { + X509_REVOKED revoked; + int k; + char *p, buf1[X509_NAME_MAXLEN], buf2[X509_NAME_MAXLEN]; + + if (_crl == NULL) return(1); + revoked.serialNumber = X509_get_serialNumber(_cert); + k = sk_X509_REVOKED_find(_crl->crl->revoked, &revoked); + if (k < 0) return(0); + + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CERT_REVOKED); + /* yes, revoked. print log and ...*/ + p = ssh_ASN1_INTEGER_2_string(revoked.serialNumber); + X509_NAME_oneline(X509_get_subject_name(_cert), buf1, sizeof(buf1)); + X509_NAME_oneline(X509_CRL_get_issuer (_crl ), buf2, sizeof(buf2)); + + error("certificate '%.*s' with serial '%.40s' revoked from issuer '%.*s'" + , (int) sizeof(buf1), buf1 + , p + , (int) sizeof(buf2), buf2); + xfree(p); + + return(1); +} + + +static int +ssh_x509revoked_cb(int ok, X509_STORE_CTX *ctx) { + X509 *cert; + X509_OBJECT xobj; + + if (!ok) return(0); + if (x509revoked == NULL) + return(ok); /* XXX:hmm */ + + cert = X509_STORE_CTX_get_current_cert(ctx); + if (cert == NULL) { + error("ssh_x509revoked_cb: missing current certificate in x509store context"); + return(0); + } + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char buf[X509_NAME_MAXLEN]; + + X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); + debug3("ssh_x509revoked_cb: issuer =%.*s", (int) sizeof(buf), buf); + + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + debug3("ssh_x509revoked_cb: subject=%.*s", (int) sizeof(buf), buf); + } + + memset(&xobj, 0, sizeof(xobj)); +/* TODO: + * NID_crl_distribution_points may contain one or more + * CRLissuer != cert issuer + */ + if (ssh_x509store_lookup( + x509revoked, X509_LU_CRL, + X509_get_subject_name(cert), + &xobj) > 0) { +/* + * In callback we cannot check CRL signature at this point when we use + * X509_get_issuer_name(), because we don't know issuer public key! + * Of course we can get the public key from X509_STORE defined by + * static variable "x509store". + * Of course we can check revocation outside callback, but we should + * try to find public key in X509_STORE[s]. + * + * At this point we can get easy public key of "current certificate"! + * + * Method: "look forward" + * At this call we check CLR (signature and other) issued with "current + * certificate" ("CertA"). If all is OK with "CertA" by next call of + * callback method "current certificate" is signed from "CertA" and the + * CRL issued from "CertA", if any is already verified - cool ;-). + * + * Note that when a certificate is revoked all signed form that + * certificate are revoked automatically too. With method "look forward" + * we already know that all issuers of "current certificate" aren't + * revoked. + */ + ok = ssh_check_crl(ctx, cert, xobj.data.crl); + } else { + if (ssh_x509flags.mandatory_crl == 1) { + int loc; + loc = X509_get_ext_by_NID(cert, NID_crl_distribution_points, -1); + ok = (loc < 0); + if (!ok) { + error("ssh_x509revoked_cb: unable to get issued CRL"); + X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNABLE_TO_GET_CRL); + } + } + } + X509_OBJECT_free_contents(&xobj); + if (!ok) return(0); + + memset(&xobj, 0, sizeof(xobj)); + if (ssh_x509store_lookup( + x509revoked, X509_LU_CRL, + X509_get_issuer_name(cert), + &xobj) > 0) { + ok = !ssh_is_cert_revoked(ctx, xobj.data.crl, cert); + } + X509_OBJECT_free_contents(&xobj); + /* clear rest of errors in OpenSSL "error buffer" */ + ERR_clear_error(); + + if (!ok) return(0); + + /**/ + return(ok); +} +#endif + +#endif /*ndef SSH_X509STORE_DISABLED*/ diff -ruN openssh-4.2p1/x509store.h openssh-4.2p1+x509-5.5/x509store.h --- openssh-4.2p1/x509store.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.2p1+x509-5.5/x509store.h 2006-04-25 22:08:01.000000000 +0300 @@ -0,0 +1,122 @@ +#ifndef X509STORE_H +#define X509STORE_H +/* + * Copyright (c) 2002-2006 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" +#include + + +#define X509_NAME_MAXLEN 512 + + +int ssh_x509cert_check(X509 *_cert); + + +typedef struct { + int is_server; + /* allowed client/server certificate purpose */ + int allowedcertpurpose; /* note field contain purpose index */ +#ifndef SSH_X509STORE_DISABLED + int key_allow_selfissued; /* make sense only when x509store is enabled */ + int mandatory_crl; +#endif /*ndef SSH_X509STORE_DISABLED*/ +} SSH_X509Flags; + +extern SSH_X509Flags ssh_x509flags; + +void ssh_x509flags_initialize(SSH_X509Flags *flags, int is_server); +void ssh_x509flags_defaults(SSH_X509Flags *flags); + +/* return purpose index, not purpose id (!) */ +int ssh_get_x509purpose_s(int _is_server, const char* _purpose_synonym); + + +#ifndef SSH_X509STORE_DISABLED +int ssh_X509_NAME_cmp(X509_NAME *_a, X509_NAME *_b); +int/*bool*/ ssh_is_selfsigned(X509 *_cert); + +int ssh_x509store_lookup(X509_STORE *store, int type, X509_NAME *name, X509_OBJECT *xobj); + +typedef struct { + /* ssh PKI(X509) store */ + const char *certificate_file; + const char *certificate_path; + const char *revocation_file; + const char *revocation_path; +#ifdef LDAP_ENABLED + const char *ldap_ver; + const char *ldap_url; +#endif +} X509StoreOptions; + +void ssh_x509store_initialize(X509StoreOptions *options); +void ssh_x509store_system_defaults(X509StoreOptions *options); +void ssh_x509store_user_defaults(X509StoreOptions *options, uid_t uid); + +int/*bool*/ ssh_x509store_addlocations(const X509StoreOptions *_locations); + +#endif /*ndef SSH_X509STORE_DISABLED*/ + + +#ifdef SSH_X509STORE_DISABLED +#ifdef LDAP_ENABLED +# include "cannot enable LDAP when x509store is disabled" +#endif /*def LDAP_ENABLED*/ +#ifdef SSH_OCSP_ENABLED +# include "cannot enable OCSP when x509store is disabled" +#endif /*def SSH_OCSP_ENABLED*/ +#endif /*def SSH_X509STORE_DISABLED*/ + + +#ifdef SSH_OCSP_ENABLED + +enum va_type { + SSHVA_NONE, + SSHVA_OCSP_CERT, + SSHVA_OCSP_SPEC +}; + + +typedef struct { + int type; /*allowed values from enum va_type*/ + + /* file with additional trusted certificates */ + const char *certificate_file; + + /* ssh OCSP Provider(Respoder) URL */ + const char *responder_url; +} VAOptions; + +int ssh_get_default_vatype(void); +int ssh_get_vatype_s(const char* type); + +void ssh_set_validator(const VAOptions *_va); /*fatal on error*/ + +int ssh_ocsp_validate(X509 *cert, X509_STORE *x509store); + +#endif /*def SSH_OCSP_ENABLED*/ + + +#endif /* X509STORE_H */