diff -ruN openssh-4.5p1/aclocal.m4 openssh-4.5p1+x509-6.1/aclocal.m4 --- openssh-4.5p1/aclocal.m4 2005-09-19 19:33:39.000000000 +0300 +++ openssh-4.5p1+x509-6.1/aclocal.m4 2007-10-25 19:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -dnl $Id: aclocal.m4,v 1.6 2005/09/19 16:33:39 tim Exp $ +dnl $Id$ dnl dnl OpenSSH-specific autoconf macros dnl @@ -84,3 +84,221 @@ #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) +]) + + +# AC_LDAP_FUNCS(FUNCTION...) +# -------------------------------- +AC_DEFUN([AC_LDAP_FUNCS], +[ +dnl +dnl Check ldap functions +dnl +AC_REQUIRE([AC_WITH_LDAP]) +if test "x$ac_ldap" = "xyes"; then + ac_save_CPPFLAGS="$CPPFLAGS" + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + LDFLAGS="$LDFLAGS $LDAP_LDFLAGS" + LIBS="$LDAP_LIBS $LIBS" + AC_CHECK_FUNCS([$1],[],[]) + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS" +fi +]) diff -ruN openssh-4.5p1/auth2-hostbased.c openssh-4.5p1+x509-6.1/auth2-hostbased.c --- openssh-4.5p1/auth2-hostbased.c 2006-08-05 05:39:39.000000000 +0300 +++ openssh-4.5p1+x509-6.1/auth2-hostbased.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.11 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -53,6 +53,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) { @@ -90,6 +92,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); @@ -136,6 +143,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.5p1/auth2-pubkey.c openssh-4.5p1+x509-6.1/auth2-pubkey.c --- openssh-4.5p1/auth2-pubkey.c 2006-08-05 05:39:39.000000000 +0300 +++ openssh-4.5p1+x509-6.1/auth2-pubkey.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,6 +1,8 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.15 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD$ */ /* * 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 @@ -31,6 +33,9 @@ #include #include #include +#ifdef HAVE_STRING_H +# include +#endif #include "xmalloc.h" #include "ssh.h" @@ -51,6 +56,7 @@ #include "ssh-gss.h" #endif #include "monitor_wrap.h" +#include "ssh-x509.h" #include "misc.h" /* import */ @@ -58,6 +64,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) { @@ -94,6 +102,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); @@ -175,6 +188,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 (!ssh_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"); + ssh_x509flags.key_allow_selfissued = 0; + if (ssh_x509cert_check(key->x509) == 1) { + /* the certificated is trusted by x509store */ + ssh_x509flags.key_allow_selfissued = 1; + return(1); + } + ssh_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) @@ -225,7 +353,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); @@ -239,20 +368,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.5p1/authfd.c openssh-4.5p1+x509-6.1/authfd.c --- openssh-4.5p1/authfd.c 2006-09-01 08:38:36.000000000 +0300 +++ openssh-4.5p1+x509-6.1/authfd.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.80 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -13,6 +13,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 @@ -476,6 +478,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); @@ -484,6 +487,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); @@ -491,6 +495,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); } @@ -518,6 +537,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; @@ -571,7 +592,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.5p1/authfile.c openssh-4.5p1+x509-6.1/authfile.c --- openssh-4.5p1/authfile.c 2006-09-01 08:38:36.000000000 +0300 +++ openssh-4.5p1+x509-6.1/authfile.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.76 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -14,6 +14,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 @@ -63,6 +65,7 @@ #include "log.h" #include "authfile.h" #include "rsa.h" +#include "ssh-x509.h" #include "misc.h" #include "atomicio.h" @@ -210,6 +213,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; @@ -225,6 +232,8 @@ comment); case KEY_DSA: case KEY_RSA: + case KEY_X509_RSA: + case KEY_X509_DSA: return key_save_private_pem(key, filename, passphrase, comment); default: @@ -470,6 +479,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)); @@ -507,6 +517,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); @@ -656,6 +674,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.5p1/config.h.in openssh-4.5p1+x509-6.1/config.h.in --- openssh-4.5p1/config.h.in 2006-11-07 15:07:01.000000000 +0200 +++ openssh-4.5p1+x509-6.1/config.h.in 2007-10-25 19:06:01.000000000 +0300 @@ -285,6 +285,18 @@ /* Define if your system has /etc/default/login */ #undef HAVE_ETC_DEFAULT_LOGIN +/* Define to 1 if `cleanup' is member of `EVP_MD'. */ +#undef HAVE_EVP_MD_CLEANUP + +/* Define to 1 if `copy' is member of `EVP_MD'. */ +#undef HAVE_EVP_MD_COPY + +/* Define to 1 if `md_data' is member of `EVP_MD_CTX'. */ +#undef HAVE_EVP_MD_CTX_MD_DATA + +/* Define to 1 if `flags' is member of `EVP_MD'. */ +#undef HAVE_EVP_MD_FLAGS + /* Define to 1 if you have the `EVP_sha256' function. */ #undef HAVE_EVP_SHA256 @@ -468,6 +480,24 @@ /* 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 `ldap_initialize' function. */ +#undef HAVE_LDAP_INITIALIZE + +/* Define to 1 if you have the `ldap_parse_result' function. */ +#undef HAVE_LDAP_PARSE_RESULT + +/* Define to 1 if you have the `ldap_sasl_bind_s' function. */ +#undef HAVE_LDAP_SASL_BIND_S + +/* Define to 1 if you have the `ldap_search_ext_s' function. */ +#undef HAVE_LDAP_SEARCH_EXT_S + /* Define to 1 if you have the `bsm' library (-lbsm). */ #undef HAVE_LIBBSM @@ -582,6 +612,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 @@ -1030,6 +1063,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 @@ -1075,6 +1111,9 @@ /* Define if you want Kerberos 5 support */ #undef KRB5 +/* Define if you want to enable LDAP queries */ +#undef LDAP_ENABLED + /* Define if you want TCP Wrappers support */ #undef LIBWRAP @@ -1208,6 +1247,9 @@ bsd-setproctitle.c */ #undef SPT_TYPE +/* Specify location of ssh CA root */ +#undef SSHCADIR + /* Define if sshd somehow reacquires a controlling TTY after setsid() */ #undef SSHD_ACQUIRES_CTTY @@ -1217,6 +1259,13 @@ /* 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 + /* non-privileged user for privilege separation */ #undef SSH_PRIVSEP_USER @@ -1238,6 +1287,9 @@ /* Prepend the address family to IP tunnel traffic */ #undef SSH_TUN_PREPEND_AF +/* 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.5p1/configure openssh-4.5p1+x509-6.1/configure --- openssh-4.5p1/configure 2006-11-07 15:07:18.000000000 +0200 +++ openssh-4.5p1+x509-6.1/configure 2007-10-25 19:06:02.000000000 +0300 @@ -199,7 +199,7 @@ echo as_func_ret_failure succeeded. fi -if (set x; as_func_ret_success y && test x = \"\$1\" ); then +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 @@ -401,7 +401,7 @@ echo as_func_ret_failure succeeded. fi -if (set x; as_func_ret_success y && test x = \"\$1\" ); then +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 @@ -710,6 +710,17 @@ 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' @@ -1299,6 +1310,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 + --disable-ocsp Disable 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 @@ -1347,6 +1361,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 @@ -31462,6 +31485,1788 @@ 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 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 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 + + +# enable/disable OCSP requests +# Check whether --enable-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 + { { 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 + ssh_ocsp="yes" + else + ssh_ocsp="no" + fi + +else + + if test "x$ssh_x509store" = "xyes"; then + ssh_ocsp="yes" + else + ssh_ocsp="no" + { echo "$as_me:$LINENO: x509store is disabled - skiping OCSP" >&5 +echo "$as_me: x509store is disabled - skiping OCSP" >&6;} + 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 { as_var=$as_ac_var; eval "test \"\${$as_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 GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +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 +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&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 { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core 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 { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 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 was given. +if test "${with_ldap_prefix+set}" = set; then + withval=$with_ldap_prefix; ac_ldap_prefix="$withval" + +fi + + + +# Check whether --with-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 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 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 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 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 { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&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 { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core 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 { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&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 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 GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ldap_init (); +int +main () +{ +return ldap_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core 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 GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ldap_init (); +int +main () +{ +return ldap_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core 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 + + +if test "x$ac_ldap" = "xyes"; then + ac_save_CPPFLAGS="$CPPFLAGS" + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + LDFLAGS="$LDFLAGS $LDAP_LDFLAGS" + LIBS="$LDAP_LIBS $LIBS" + + + + +for ac_func in \ + ldap_initialize \ + ldap_parse_result \ + ldap_sasl_bind_s \ + ldap_search_ext_s \ + +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 { as_var=$as_ac_var; eval "test \"\${$as_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 GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +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 +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS" +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: WARNING: cross compiling: assuming no" >&5 +echo "$as_me: WARNING: cross compiling: assuming no" >&2;} + ssh_x509dn_email="no" + + +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 { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core.conftest.* 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 { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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 core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core 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 + +# Check for the existence of "EVP_MD members" +{ echo "$as_me:$LINENO: checking for EVP_MD.flags" >&5 +echo $ECHO_N "checking for EVP_MD.flags... $ECHO_C" >&6; } +if test "${ac_cv_member_EVP_MD_flags+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 EVP_MD ac_aggr; +if (ac_aggr.flags) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_flags=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 EVP_MD ac_aggr; +if (sizeof ac_aggr.flags) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_flags=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_EVP_MD_flags=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_EVP_MD_flags" >&5 +echo "${ECHO_T}$ac_cv_member_EVP_MD_flags" >&6; } +if test $ac_cv_member_EVP_MD_flags = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_EVP_MD_FLAGS 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for EVP_MD.copy" >&5 +echo $ECHO_N "checking for EVP_MD.copy... $ECHO_C" >&6; } +if test "${ac_cv_member_EVP_MD_copy+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 EVP_MD ac_aggr; +if (ac_aggr.copy) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_copy=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 EVP_MD ac_aggr; +if (sizeof ac_aggr.copy) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_copy=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_EVP_MD_copy=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_EVP_MD_copy" >&5 +echo "${ECHO_T}$ac_cv_member_EVP_MD_copy" >&6; } +if test $ac_cv_member_EVP_MD_copy = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_EVP_MD_COPY 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for EVP_MD.cleanup" >&5 +echo $ECHO_N "checking for EVP_MD.cleanup... $ECHO_C" >&6; } +if test "${ac_cv_member_EVP_MD_cleanup+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 EVP_MD ac_aggr; +if (ac_aggr.cleanup) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_cleanup=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 EVP_MD ac_aggr; +if (sizeof ac_aggr.cleanup) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_cleanup=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_EVP_MD_cleanup=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_EVP_MD_cleanup" >&5 +echo "${ECHO_T}$ac_cv_member_EVP_MD_cleanup" >&6; } +if test $ac_cv_member_EVP_MD_cleanup = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_EVP_MD_CLEANUP 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for EVP_MD_CTX.md_data" >&5 +echo $ECHO_N "checking for EVP_MD_CTX.md_data... $ECHO_C" >&6; } +if test "${ac_cv_member_EVP_MD_CTX_md_data+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 EVP_MD_CTX ac_aggr; +if (ac_aggr.md_data) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_CTX_md_data=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 EVP_MD_CTX ac_aggr; +if (sizeof ac_aggr.md_data) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&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' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_EVP_MD_CTX_md_data=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_EVP_MD_CTX_md_data=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_EVP_MD_CTX_md_data" >&5 +echo "${ECHO_T}$ac_cv_member_EVP_MD_CTX_md_data" >&6; } +if test $ac_cv_member_EVP_MD_CTX_md_data = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_EVP_MD_CTX_MD_DATA 1 +_ACEOF + + +fi + + # Where to place sshd.pid piddir=/var/run # make sure the directory exists @@ -32169,7 +33974,7 @@ CFLAGS="$CFLAGS $werror_flags" -ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openssh.xml openbsd-compat/Makefile openbsd-compat/regress/Makefile scard/Makefile ssh_prng_cmds survey.sh" +ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openssh.xml openbsd-compat/Makefile openbsd-compat/regress/Makefile scard/Makefile ssh_prng_cmds survey.sh tests/CA/Makefile tests/CA/env" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -32721,6 +34526,8 @@ "scard/Makefile") CONFIG_FILES="$CONFIG_FILES scard/Makefile" ;; "ssh_prng_cmds") CONFIG_FILES="$CONFIG_FILES ssh_prng_cmds" ;; "survey.sh") CONFIG_FILES="$CONFIG_FILES survey.sh" ;; + "tests/CA/Makefile") CONFIG_FILES="$CONFIG_FILES tests/CA/Makefile" ;; + "tests/CA/env") CONFIG_FILES="$CONFIG_FILES tests/CA/env" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} @@ -32932,12 +34739,23 @@ MANTYPE!$MANTYPE$ac_delim mansubdir!$mansubdir$ac_delim user_path!$user_path$ac_delim +sshcadir!$sshcadir$ac_delim +OCSP_ON!$OCSP_ON$ac_delim +OCSP_OFF!$OCSP_OFF$ac_delim +LDAP_BINDIR!$LDAP_BINDIR$ac_delim +LDAP_LIBEXECDIR!$LDAP_LIBEXECDIR$ac_delim +LDAP_SYSCONFDIR!$LDAP_SYSCONFDIR$ac_delim +LDAP_LDFLAGS!$LDAP_LDFLAGS$ac_delim +LDAP_CPPFLAGS!$LDAP_CPPFLAGS$ac_delim +LDAP_LIBS!$LDAP_LIBS$ac_delim +LDAP_ON!$LDAP_ON$ac_delim +LDAP_OFF!$LDAP_OFF$ac_delim piddir!$piddir$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 26; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -33386,6 +35204,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" @@ -33412,6 +35231,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 " Solaris process contract support: $SPC_MSG" echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" @@ -33438,6 +35260,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.5p1/configure.ac openssh-4.5p1+x509-6.1/configure.ac --- openssh-4.5p1/configure.ac 2006-10-07 02:07:21.000000000 +0300 +++ openssh-4.5p1+x509-6.1/configure.ac 2007-10-25 19:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -# $Id: configure.ac,v 1.370 2006/10/06 23:07:21 dtucker Exp $ +# $Id$ # # Copyright (c) 1999-2004 Damien Miller # @@ -3620,6 +3620,160 @@ ] ) +# 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 + + +# enable/disable OCSP requests +AC_ARG_ENABLE(ocsp, + [ --disable-ocsp Disable OCSP validation], + [ + if test "x$enableval" = "xyes"; then + if test "x$ssh_x509store" != "xyes"; then + AC_MSG_ERROR([cannot enable OCSP when x509store is disabled]) + fi + ssh_ocsp="yes" + else + ssh_ocsp="no" + fi + ], + [ + if test "x$ssh_x509store" = "xyes"; then + ssh_ocsp="yes" + else + ssh_ocsp="no" + AC_MSG_NOTICE([x509store is disabled - skiping OCSP]) + 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 + AC_LDAP_FUNCS([\ + ldap_initialize \ + ldap_parse_result \ + ldap_sasl_bind_s \ + ldap_search_ext_s \ + ]) +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_RUN_IFELSE( + [AC_LANG_SOURCE([ +#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" + ], + [ + AC_MSG_WARN([cross compiling: assuming 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 + +# Check for the existence of "EVP_MD members" +AC_CHECK_MEMBERS([EVP_MD.flags],,,[#include ]) +AC_CHECK_MEMBERS([EVP_MD.copy],,,[#include ]) +AC_CHECK_MEMBERS([EVP_MD.cleanup],,,[#include ]) +AC_CHECK_MEMBERS([EVP_MD_CTX.md_data],,,[#include ]) + # Where to place sshd.pid piddir=/var/run # make sure the directory exists @@ -3922,7 +4076,8 @@ AC_EXEEXT AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \ openbsd-compat/Makefile openbsd-compat/regress/Makefile \ - scard/Makefile ssh_prng_cmds survey.sh]) + scard/Makefile ssh_prng_cmds survey.sh \ + tests/CA/Makefile tests/CA/env]) AC_OUTPUT # Print summary of options @@ -3944,6 +4099,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" @@ -3970,6 +4126,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 " Solaris process contract support: $SPC_MSG" echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" @@ -3996,6 +4155,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.5p1/dns.c openssh-4.5p1+x509-6.1/dns.c --- openssh-4.5p1/dns.c 2006-09-01 08:38:36.000000000 +0300 +++ openssh-4.5p1+x509-6.1/dns.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,9 +1,12 @@ -/* $OpenBSD: dns.c,v 1.23 2006/08/03 03:34:42 deraadt 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,9 +40,24 @@ #include "xmalloc.h" #include "key.h" +#include "ssh-x509.h" #include "dns.h" #include "log.h" + +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; + + static const char *errset_text[] = { "success", /* 0 ERRSET_SUCCESS */ "out of memory", /* 1 ERRSET_NOMEMORY */ @@ -106,6 +124,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. */ @@ -158,6 +328,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 */ @@ -190,6 +481,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) { @@ -268,10 +567,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)) { @@ -292,5 +638,6 @@ error("export_dns_rr: unsupported algorithm"); } + cert_param_clean(&cert_param); return success; } diff -ruN openssh-4.5p1/dns.h openssh-4.5p1+x509-6.1/dns.h --- openssh-4.5p1/dns.h 2006-08-05 05:39:40.000000000 +0300 +++ openssh-4.5p1+x509-6.1/dns.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,9 +1,12 @@ -/* $OpenBSD: dns.h,v 1.10 2006/08/03 03:34:42 deraadt 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: @@ -34,12 +37,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.5p1/hostfile.c openssh-4.5p1+x509-6.1/hostfile.c --- openssh-4.5p1/hostfile.c 2006-09-01 08:38:36.000000000 +0300 +++ openssh-4.5p1+x509-6.1/hostfile.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.45 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -14,6 +14,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 @@ -56,6 +58,7 @@ #include "key.h" #include "hostfile.h" #include "log.h" +#include "ssh-x509.h" static int extract_salt(const char *s, u_int l, char *salt, size_t salt_len) @@ -342,7 +345,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.5p1/INSTALL openssh-4.5p1+x509-6.1/INSTALL --- openssh-4.5p1/INSTALL 2006-09-17 15:55:52.000000000 +0300 +++ openssh-4.5p1+x509-6.1/INSTALL 2006-11-08 09:06:00.000000000 +0200 @@ -82,6 +82,9 @@ implementation (http://www.openbsm.org). +X.509 certificate support: +http://roumenpetrov.info/openssh + 2. Building / Installation -------------------------- @@ -196,6 +199,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: @@ -250,4 +262,4 @@ http://www.openssh.com/ -$Id: INSTALL,v 1.76 2006/09/17 12:55:52 dtucker Exp $ +$Id$ diff -ruN openssh-4.5p1/key.c openssh-4.5p1+x509-6.1/key.c --- openssh-4.5p1/key.c 2006-11-07 14:14:42.000000000 +0200 +++ openssh-4.5p1+x509-6.1/key.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.68 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD$ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -11,6 +11,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 @@ -46,6 +48,7 @@ #include "xmalloc.h" #include "key.h" #include "rsa.h" +#include "ssh-x509.h" #include "uuencode.h" #include "buffer.h" #include "log.h" @@ -60,9 +63,11 @@ k->type = type; 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) @@ -70,8 +75,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) @@ -83,6 +93,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; @@ -100,6 +114,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) @@ -112,10 +127,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; @@ -142,6 +172,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: @@ -159,15 +204,27 @@ 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; 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; +#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; @@ -210,6 +267,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: @@ -413,6 +472,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"); @@ -437,6 +498,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); @@ -456,7 +522,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); @@ -523,6 +612,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,12 @@ return "RSA"; case KEY_DSA: return "DSA"; + case KEY_X509_RSA: + if(k->rsa) return "RSA+cert"; + return "X509(rsa)"; + case KEY_X509_DSA: + if(k->dsa) return "DSA+cert"; + return "X509(dsa)"; } return "unknown"; } @@ -544,6 +641,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"; @@ -562,6 +664,9 @@ return BN_num_bits(k->rsa->n); case KEY_DSA: return BN_num_bits(k->dsa->p); + case KEY_X509_RSA: + case KEY_X509_DSA: + return ssh_x509_key_size(k); } return 0; } @@ -640,6 +745,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 +794,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 +810,7 @@ } type = key_type_from_name(ktype); + debug3("key_from_blob(..., ...) ktype=%.30s", ktype); switch (type) { case KEY_RSA: @@ -767,6 +882,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); @@ -795,6 +915,10 @@ return ssh_dss_sign(key, sigp, lenp, data, datalen); case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); + 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; @@ -819,6 +943,10 @@ return ssh_dss_verify(key, signature, signaturelen, data, datalen); case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + 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; @@ -840,6 +968,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) @@ -848,6 +977,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) @@ -860,9 +990,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.5p1/key.h openssh-4.5p1+x509-6.1/key.h --- openssh-4.5p1/key.h 2006-08-05 05:39:40.000000000 +0300 +++ openssh-4.5p1+x509-6.1/key.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,7 +1,9 @@ -/* $OpenBSD: key.h,v 1.26 2006/08/03 03:34:42 deraadt 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.5p1/LICENCE openssh-4.5p1+x509-6.1/LICENCE --- openssh-4.5p1/LICENCE 2006-08-30 20:24:41.000000000 +0300 +++ openssh-4.5p1+x509-6.1/LICENCE 2006-11-08 09:06:00.000000000 +0200 @@ -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: @@ -334,4 +335,4 @@ ------ -$OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $ +$OpenBSD$ diff -ruN openssh-4.5p1/log.c openssh-4.5p1+x509-6.1/log.c --- openssh-4.5p1/log.c 2006-08-20 10:55:55.000000000 +0300 +++ openssh-4.5p1+x509-6.1/log.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.39 2006/08/18 09:13:25 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -301,6 +301,11 @@ #endif } +LogLevel +get_log_level(void) { + return log_level; +} + #define MSGBUFSIZ 1024 void diff -ruN openssh-4.5p1/log.h openssh-4.5p1+x509-6.1/log.h --- openssh-4.5p1/log.h 2006-08-18 17:32:21.000000000 +0300 +++ openssh-4.5p1+x509-6.1/log.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: log.h,v 1.15 2006/08/18 09:13:25 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -47,6 +47,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.5p1/m4/ldap.m4 openssh-4.5p1+x509-6.1/m4/ldap.m4 --- openssh-4.5p1/m4/ldap.m4 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/m4/ldap.m4 2007-10-22 23:05:29.000000000 +0300 @@ -0,0 +1,217 @@ +# Options to build with LDAP +# +# Author: Roumen Petrov +# Revision: 22 Oct 2007 +# +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) +]) + + +# AC_LDAP_FUNCS(FUNCTION...) +# -------------------------------- +AC_DEFUN([AC_LDAP_FUNCS], +[ +dnl +dnl Check ldap functions +dnl +AC_REQUIRE([AC_WITH_LDAP]) +if test "x$ac_ldap" = "xyes"; then + ac_save_CPPFLAGS="$CPPFLAGS" + ac_save_LDFLAGS="$LDFLAGS" + ac_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $LDAP_CPPFLAGS" + LDFLAGS="$LDFLAGS $LDAP_LDFLAGS" + LIBS="$LDAP_LIBS $LIBS" + AC_CHECK_FUNCS([$1],[],[]) + LIBS="$ac_save_LIBS" + LDFLAGS="$ac_save_LDFLAGS" + CPPFLAGS="$ac_save_CPPFLAGS" +fi +]) diff -ruN openssh-4.5p1/Makefile.in openssh-4.5p1+x509-6.1/Makefile.in --- openssh-4.5p1/Makefile.in 2006-10-24 00:44:47.000000000 +0300 +++ openssh-4.5p1+x509-6.1/Makefile.in 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.283 2006/10/23 21:44:47 tim Exp $ +# $Id$ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -15,6 +15,7 @@ mandir=@mandir@ mansubdir=@mansubdir@ sysconfdir=@sysconfdir@ +sshcadir=@sshcadir@ piddir=@piddir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ @@ -31,6 +32,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)\" \ @@ -42,13 +44,14 @@ CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ -CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ +CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ @LDAP_CPPFLAGS@ $(PATHS) @DEFS@ LIBS=@LIBS@ LIBSELINUX=@LIBSELINUX@ SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ LIBPAM=@LIBPAM@ LIBWRAP=@LIBWRAP@ +LIBLDAP=@LDAP_LDFLAGS@ @LDAP_LIBS@ AR=@AR@ AWK=@AWK@ RANLIB=@RANLIB@ @@ -63,6 +66,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 bufbn.o buffer.o \ @@ -72,12 +84,12 @@ log.o match.o md-sha256.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 \ @@ -89,7 +101,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 platform.o + audit.o audit-bsm.o platform.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 @@ -108,6 +120,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/ssh/sshrc|$(sysconfdir)/sshrc|g' \ @@ -136,10 +152,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) $(LIBSELINUX) $(SSHDLIBS) $(LIBS) + $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBWRAP) $(LIBPAM) $(LIBLDAP) $(LIBSELINUX) $(SSHDLIBS) $(LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) @@ -153,8 +169,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) @@ -210,6 +226,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 @@ -253,6 +270,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 @@ -381,7 +400,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 ] || \ @@ -412,7 +438,23 @@ 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" \ + $@ ) + compat-tests: $(LIBCOMPAT) (cd openbsd-compat/regress && $(MAKE)) @@ -421,6 +463,7 @@ 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.5p1/pathnames.h openssh-4.5p1+x509-6.1/pathnames.h --- openssh-4.5p1/pathnames.h 2006-03-26 06:30:02.000000000 +0300 +++ openssh-4.5p1+x509-6.1/pathnames.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.16 2006/03/25 22:22:43 djm 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.5p1/readconf.c openssh-4.5p1+x509-6.1/readconf.c --- openssh-4.5p1/readconf.c 2006-09-01 08:38:37.000000000 +0300 +++ openssh-4.5p1+x509-6.1/readconf.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.159 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -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". + * + * 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" @@ -41,6 +64,8 @@ #include "misc.h" #include "buffer.h" #include "kex.h" +#include "myproposal.h" +#include "ssh-xkalg.h" #include "mac.h" /* Format of the configuration file: @@ -129,6 +154,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, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oDeprecated, oUnsupported } OpCodes; @@ -222,6 +259,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 }, { "tunnel", oTunnel }, { "tunneldevice", oTunnelDevice }, { "localcommand", oLocalCommand }, @@ -671,9 +728,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; @@ -915,11 +974,180 @@ intptr = &options->permit_local_command; 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); @@ -1060,6 +1288,20 @@ 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*/ options->tun_open = -1; options->tun_local = -1; options->tun_remote = -1; @@ -1067,6 +1309,22 @@ options->permit_local_command = -1; } +#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 * options for which no value has been specified with their default values. @@ -1134,7 +1392,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) { @@ -1205,6 +1463,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.5p1/readconf.h openssh-4.5p1+x509-6.1/readconf.h --- openssh-4.5p1/readconf.h 2006-08-05 05:39:40.000000000 +0300 +++ openssh-4.5p1+x509-6.1/readconf.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.71 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -11,11 +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 "x509store.h" + /* Data structure for representing a forwarding request. */ typedef struct { @@ -114,6 +139,24 @@ 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*/ + int tun_open; /* tun(4) */ int tun_local; /* force tun device (optional) */ int tun_remote; /* force tun device (optional) */ diff -ruN openssh-4.5p1/README.x509v3 openssh-4.5p1+x509-6.1/README.x509v3 --- openssh-4.5p1/README.x509v3 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/README.x509v3 2007-10-24 00:53:39.000000000 +0300 @@ -0,0 +1,512 @@ + Roumen Petrov + Sofia, Bulgaria + Wed Oct 24 2007 + +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 -nameopt oneline + +- can be in RFC2253 format like output from command: +$ openssl x509 -noout -subject -in A_CERTIFICATE_FILE -nameopt RFC2253 + +IMPORTANT NOTE (if a distinguished name contain non-ascii character): +- for versions 6.+: + ALWAIS use "openssl x509" command option -nameopt ! + The parser don't and willn't support output without -nameopt +- for versions prior 6.0: + The program could'not parse subject. Use "blob" format (see below). + +- 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 \ + -nameopt oneline \ + ) >> $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.5p1/scp.0 openssh-4.5p1+x509-6.1/scp.0 --- openssh-4.5p1/scp.0 2006-11-07 15:07:19.000000000 +0200 +++ openssh-4.5p1+x509-6.1/scp.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SCP(1) OpenBSD Reference Manual SCP(1) +SCP(1) BSD General Commands Manual SCP(1) NAME - scp - secure copy (remote file copy program) + scp -- secure copy (remote file copy program) SYNOPSIS scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] @@ -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,61 +54,11 @@ 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 - RekeyLimit - 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 - this option is written with a capital `P', because -p is already + this option is written with a capital 'P', because -p is already reserved for preserving the times and modes of the file in rcp(1). @@ -141,4 +91,4 @@ Timo Rinne Tatu Ylonen -OpenBSD 4.0 September 25, 1999 3 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/scp.1 openssh-4.5p1+x509-6.1/scp.1 --- openssh-4.5p1/scp.1 2006-07-24 07:04:36.000000000 +0300 +++ openssh-4.5p1+x509-6.1/scp.1 2006-11-08 09:06:00.000000000 +0200 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.40 2006/07/18 07:56:28 jmc Exp $ +.\" $OpenBSD$ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -113,59 +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 RekeyLimit -.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.5p1/servconf.c openssh-4.5p1+x509-6.1/servconf.c --- openssh-4.5p1/servconf.c 2006-08-18 17:23:15.000000000 +0300 +++ openssh-4.5p1+x509-6.1/servconf.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.165 2006/08/14 12:40:25 dtucker Exp $ */ +/* $OpenBSD$ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -8,6 +8,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". + * + * 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" @@ -29,6 +52,7 @@ #include "log.h" #include "buffer.h" #include "servconf.h" +#include "ssh-xkalg.h" #include "compat.h" #include "pathnames.h" #include "misc.h" @@ -122,6 +146,18 @@ options->permit_tun = -1; options->num_permitted_opens = -1; options->adm_forced_command = NULL; + + options->hostbased_algorithms = NULL; + options->pubkey_algorithms = NULL; + 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*/ } void @@ -250,6 +286,21 @@ if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; + /* options->hostbased_algorithms */ + /* options->pubkey_algorithms */ + fill_default_xkalg(); + ssh_x509flags_defaults(&options->x509flags); + memcpy(&ssh_x509flags, &options->x509flags, sizeof(ssh_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; @@ -262,7 +313,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. */ @@ -293,6 +351,16 @@ sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sUsePrivilegeSeparation, + sHostbasedAlgorithms, + sPubkeyAlgorithms, + sX509KeyAlgorithm, + sAllowedClientCertPurpose, + sKeyAllowSelfIssued, sMandatoryCRL, + sCACertificateFile, sCACertificatePath, + sCARevocationFile, sCARevocationPath, + sCAldapVersion, sCAldapURL, + sVAType, sVACertificateFile, + sVAOCSPResponderURL, sDeprecated, sUnsupported } ServerOpCodes; @@ -399,6 +467,22 @@ { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL }, { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL }, { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL }, + { "hostbasedalgorithms", sHostbasedAlgorithms, SSHCFG_ALL }, + { "pubkeyalgorithms", sPubkeyAlgorithms, SSHCFG_ALL }, + { "x509rsasigtype", sDeprecated, SSHCFG_GLOBAL }, + { "x509keyalgorithm", sX509KeyAlgorithm, SSHCFG_GLOBAL }, + { "allowedcertpurpose", sAllowedClientCertPurpose, SSHCFG_GLOBAL }, + { "keyallowselfissued", sKeyAllowSelfIssued, SSHCFG_GLOBAL } , + { "mandatorycrl", sMandatoryCRL, SSHCFG_GLOBAL } , + { "cacertificatefile", sCACertificateFile, SSHCFG_GLOBAL }, + { "cacertificatepath", sCACertificatePath, SSHCFG_GLOBAL }, + { "carevocationfile", sCARevocationFile, SSHCFG_GLOBAL }, + { "carevocationpath", sCARevocationPath, SSHCFG_GLOBAL }, + { "caldapversion", sCAldapVersion, SSHCFG_GLOBAL }, + { "caldapurl", sCAldapURL, SSHCFG_GLOBAL }, + { "vatype", sVAType, SSHCFG_GLOBAL }, + { "vacertificatefile", sVACertificateFile, SSHCFG_GLOBAL }, + { "vaocspresponderurl", sVAOCSPResponderURL, SSHCFG_GLOBAL }, { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL }, { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, @@ -1253,6 +1337,142 @@ options->adm_forced_command = xstrdup(cp + len); return 0; + 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 (*activep && 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 (*activep && 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); @@ -1260,6 +1480,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); @@ -1338,6 +1575,17 @@ dst->x11_forwarding = src->x11_forwarding; if (src->x11_use_localhost != -1) dst->x11_use_localhost = src->x11_use_localhost; + + if (src->hostbased_algorithms != NULL) { + if (dst->hostbased_algorithms != NULL) + xfree(dst->hostbased_algorithms); + dst->hostbased_algorithms = src->hostbased_algorithms; + } + if (src->pubkey_algorithms != NULL) { + if (dst->pubkey_algorithms != NULL) + xfree(dst->pubkey_algorithms); + dst->pubkey_algorithms = src->pubkey_algorithms; + } } void diff -ruN openssh-4.5p1/servconf.h openssh-4.5p1+x509-6.1/servconf.h --- openssh-4.5p1/servconf.h 2006-08-18 17:23:15.000000000 +0300 +++ openssh-4.5p1+x509-6.1/servconf.h 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.79 2006/08/14 12:40:25 dtucker Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen @@ -11,11 +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 "x509store.h" + #define MAX_PORTS 256 /* Max # ports. */ #define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ @@ -138,6 +163,23 @@ 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*/ + int permit_tun; int num_permitted_opens; diff -ruN openssh-4.5p1/sftp.0 openssh-4.5p1+x509-6.1/sftp.0 --- openssh-4.5p1/sftp.0 2006-11-07 15:07:26.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sftp.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SFTP(1) OpenBSD Reference Manual SFTP(1) +SFTP(1) BSD General Commands Manual SFTP(1) NAME - sftp - secure file transfer program + sftp -- secure file transfer program SYNOPSIS sftp [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config] @@ -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,14 +37,14 @@ 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 + batchfile of '-' may be used to indicate standard input. sftp will abort if any of the following commands fail: get, put, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod, chown, chgrp, lpwd and lmkdir. Termination on error can be suppressed on a - command by command basis by prefixing the command with a `-' + command by command basis by prefixing the command with a '-' character (for example, -rm /tmp/blah*). -C Enables compression (via ssh's -C flag). @@ -58,57 +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 - RekeyLimit - 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)). @@ -136,7 +86,7 @@ those of ftp(1). Commands are case insensitive. Pathnames that contain spaces must be enclosed in quotes. Any special characters contained within pathnames that are recognized by glob(3) must be escaped with - backslashes (`\'). + backslashes ('\'). bye Quit sftp. @@ -161,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. @@ -195,7 +145,7 @@ -1 Produce single columnar output. - -a List files beginning with a dot (`.'). + -a List files beginning with a dot ('.'). -f Do not sort the listing. The default sort order is lexi- cographical. @@ -222,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. @@ -263,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 4.0 February 4, 2001 4 +BSD February 4, 2001 BSD diff -ruN openssh-4.5p1/sftp.1 openssh-4.5p1+x509-6.1/sftp.1 --- openssh-4.5p1/sftp.1 2006-01-20 02:31:47.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sftp.1 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.63 2006/01/20 00:14:55 dtucker Exp $ +.\" $OpenBSD$ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -141,59 +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 RekeyLimit -.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.5p1/sftp-server.0 openssh-4.5p1+x509-6.1/sftp-server.0 --- openssh-4.5p1/sftp-server.0 2006-11-07 15:07:25.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sftp-server.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,16 +1,16 @@ -SFTP-SERVER(8) OpenBSD System Manager's Manual SFTP-SERVER(8) +SFTP-SERVER(8) BSD System Manager's Manual SFTP-SERVER(8) NAME - sftp-server - SFTP server subsystem + sftp-server -- SFTP server subsystem SYNOPSIS sftp-server [-f log_facility] [-l log_level] 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. + stdout and expects client requests from stdin. sftp-server is not + intended to be called directly, but from sshd(8) using the Subsystem + option. Command-line flags to sftp-server should be specified in the Subsystem declaration. See sshd_config(5) for more information. @@ -25,11 +25,11 @@ -l log_level Specifies which messages will be logged by sftp-server. The pos- - sible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DE- - BUG1, DEBUG2, and DEBUG3. INFO and VERBOSE log transactions that - sftp-server performs on behalf of the client. DEBUG and DEBUG1 - are equivalent. DEBUG2 and DEBUG3 each specify higher levels of - debugging output. The default is ERROR. + sible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, + DEBUG1, DEBUG2, and DEBUG3. INFO and VERBOSE log transactions + that sftp-server performs on behalf of the client. DEBUG and + DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher + levels of debugging output. The default is ERROR. SEE ALSO sftp(1), ssh(1), sshd_config(5), sshd(8) @@ -43,4 +43,4 @@ AUTHORS Markus Friedl -OpenBSD 4.0 August 30, 2000 1 +BSD August 30, 2000 BSD diff -ruN openssh-4.5p1/ssh.0 openssh-4.5p1+x509-6.1/ssh.0 --- openssh-4.5p1/ssh.0 2006-11-07 15:07:23.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,27 +1,27 @@ -SSH(1) OpenBSD Reference Manual SSH(1) +SSH(1) BSD General Commands Manual SSH(1) NAME - ssh - OpenSSH SSH client (remote login program) + ssh -- OpenSSH SSH client (remote login program) SYNOPSIS - ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec] - [-D [bind_address:]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] + ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec] [-D + [bind_address:]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] [-w local_tun[:remote_tun]] [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 - 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 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 - one of several methods depending on the protocol version used (see be- - low). + one of several methods depending on the protocol version used (see + below). If command is specified, it is executed on the remote host instead of a login shell. @@ -52,8 +52,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 connections). The @@ -95,24 +95,24 @@ the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act - as a SOCKS server. Only root can forward privileged ports. Dy- - namic port forwardings can also be specified in the configuration - file. + as a SOCKS server. Only root can forward privileged ports. + Dynamic port forwardings can also be specified in the configura- + tion file. IPv6 addresses can be specified with an alternative syntax: [bind_address/]port or by enclosing the address in square brack- - ets. Only the superuser can forward privileged ports. By de- - fault, the local port is bound in accordance with the + ets. 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- + be bound for local use only, while an empty address or '*' indi- cates that the port should be available from all interfaces. -e escape_char - Sets the escape character for sessions with a pty (default: `~'). + Sets the escape character for sessions with a pty (default: '~'). The escape character is only recognized at the beginning of a - line. The escape character followed by a dot (`.') closes the + line. The escape character followed by a dot ('.') closes the connection; followed by control-Z suspends the connection; and followed by itself sends the escape character once. Setting the character to ``none'' disables any escapes and makes the session @@ -125,27 +125,28 @@ 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 Specify the device ssh should use to communicate with a smartcard used for storing the user's private RSA key. This option is only - available if support for smartcard devices is compiled in (de- - fault is no support). + available if support for smartcard devices is compiled in + (default is no support). -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. @@ -159,15 +160,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 @@ -175,9 +176,9 @@ -M Places the ssh client into ``master'' mode for connection shar- ing. Multiple -M options places ssh into ``master'' mode with - confirmation required before slave connections are accepted. Re- - fer to the description of ControlMaster in ssh_config(5) for de- - tails. + confirmation required before slave connections are accepted. + Refer to the description of ControlMaster in ssh_config(5) for + details. -m mac_spec Additionally, for protocol version 2 a comma-separated list of @@ -189,12 +190,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 @@ -206,72 +208,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 - ExitOnForwardFailure - ForwardAgent - ForwardX11 - ForwardX11Trusted - GatewayPorts - GlobalKnownHostsFile - GSSAPIAuthentication - GSSAPIDelegateCredentials - HashKnownHosts - Host - HostbasedAuthentication - HostKeyAlgorithms - HostKeyAlias - HostName - IdentityFile - IdentitiesOnly - KbdInteractiveDevices - LocalCommand - LocalForward - LogLevel - MACs - NoHostAuthenticationForLocalhost - NumberOfPasswordPrompts - PasswordAuthentication - PermitLocalCommand - Port - PreferredAuthentications - Protocol - ProxyCommand - PubkeyAuthentication - RekeyLimit - RemoteForward - RhostsRSAAuthentication - RSAAuthentication - SendEnv - ServerAliveInterval - ServerAliveCountMax - SmartcardDevice - StrictHostKeyChecking - TCPKeepAlive - Tunnel - TunnelDevice - 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 @@ -296,10 +234,10 @@ By default, the listening socket on the server will be bound to the loopback interface only. This may be overriden by specifying - a bind_address. An empty bind_address, or the address `*', indi- + 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- @@ -307,9 +245,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. @@ -327,8 +265,9 @@ the verbosity. The maximum is 3. -w local_tun[:remote_tun] - Requests tunnel device forwarding with the specified tun(4) de- - vices between the client (local_tun) and the server (remote_tun). + Requests tunnel device forwarding with the specified tun(4) + devices between the client (local_tun) and the server + (remote_tun). The devices may be specified by numerical ID or the keyword ``any'', which uses the next available tunnel device. If @@ -346,9 +285,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. @@ -375,10 +314,11 @@ strong mechanism for ensuring the integrity of the connection. The methods available for authentication are: GSSAPI-based authentica- - tion, host-based authentication, public key authentication, challenge-re- - sponse authentication, and password authentication. Authentication meth- - ods are tried in the order specified above, though protocol 2 has a con- - figuration option to change the default order: PreferredAuthentications. + tion, host-based authentication, public key authentication, challenge- + response authentication, and password authentication. Authentication + methods are tried in the order specified above, though protocol 2 has a + configuration option to change the default order: + PreferredAuthentications. Host-based authentication works as follows: If the machine the user logs in from is listed in /etc/hosts.equiv or /etc/shosts.equiv on the remote @@ -386,51 +326,58 @@ ~/.rhosts or ~/.shosts exist in the user's home directory on the remote machine and contain a line containing the name of the client machine and the name of the user on that machine, the user is considered for login. - Additionally, the server must be able to verify the client's host key - (see the description of /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts, - below) for login to be permitted. This authentication method closes se- - curity holes due to IP spoofing, DNS spoofing, and routing spoofing. - [Note to the administrator: /etc/hosts.equiv, ~/.rhosts, and the - rlogin/rsh protocol in general, are inherently insecure and should be - disabled if security is desired.] + Additionally, the server must be able to verify the client's host key or + certificate (see the description of /etc/ssh/ssh_known_hosts and + ~/.ssh/known_hosts, below) for login to be permitted. This authentica- + tion 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 protocol in general, are inherently inse- + cure and should be disabled if security is desired.] Public key authentication works as follows: The scheme is based on pub- - lic-key cryptography, using cryptosystems where encryption and decryption - are done using separate keys, and it is unfeasible to derive the decryp- - tion key from the encryption key. The idea is that each user creates a - public/private key pair for authentication purposes. The server knows - the public key, and only the user knows the private key. ssh implements - public key authentication protocol automatically, using either the RSA or - DSA algorithms. Protocol 1 is restricted to using only RSA keys, but - protocol 2 may use either. The HISTORY section of ssl(8) contains a - brief discussion of the two algorithms. - - The file ~/.ssh/authorized_keys lists the public keys that are permitted - for logging in. When the user logs in, the ssh program tells the server - which key pair it would like to use for authentication. The client - proves that it has access to the private key and the server checks that - the corresponding public key is authorized to accept the account. + lic-key cryptography or infrastructure (PKI), using cryptosystems where + encryption and decryption are done using separate keys, and it is unfea- + sible to derive the decryption key from the encryption key. The idea is + that each user creates a public/private key pair for authentication pur- + poses. The server knows the public key or certificate, and only the user + knows the private key. ssh implements public key authentication protocol + automatically, using either the RSA or DSA algorithms. Protocol 1 is + restricted to using only RSA keys, but protocol 2 may use either or X.509 + certificates. The HISTORY section of ssl(8) contains a brief discussion + of the two algorithms. + + The file ~/.ssh/authorized_keys lists the public keys or certificates + that are permitted for logging in. When the user logs in, the ssh pro- + gram tells the server which key pair or certificate it would like to use + for authentication. The client proves that it has access to the private + key and the server checks that the corresponding public key or certifi- + cate is authorized to accept the account. The user creates his/her key pair by running ssh-keygen(1). This stores the private key in ~/.ssh/identity (protocol 1), ~/.ssh/id_dsa (protocol 2 DSA), or ~/.ssh/id_rsa (protocol 2 RSA) and stores the public key in ~/.ssh/identity.pub (protocol 1), ~/.ssh/id_dsa.pub (protocol 2 DSA), or - ~/.ssh/id_rsa.pub (protocol 2 RSA) in the user's home directory. The us- - er should then copy the public key to ~/.ssh/authorized_keys in his/her - home directory on the remote machine. The authorized_keys file corre- - sponds to the conventional ~/.rhosts file, and has one key per line, - though the lines can be very long. After this, the user can log in with- - out giving the password. + ~/.ssh/id_rsa.pub (protocol 2 RSA) in the user's home directory. It is + possible protocol version 2 identity file to contain private key followed + by X.509 certificate that match it. In this case *.pub file must contain + that certificate. The user should then copy the public key or certifi- + cate to ~/.ssh/authorized_keys in his/her home directory on the remote + machine. In case with X.509 certificates user can use ``new style'' : + instead to add content of file to authorized_keys user can write certifi- + cate ``Distinguished Name'' - see sshd(8) manual page. The + authorized_keys file corresponds to the conventional ~/.rhosts file, and + has one key or certificate per line, though the lines can be very long. + After this, the user can log in without giving the password. The most convenient way to use public key authentication may be with an authentication agent. See ssh-agent(1) for more information. Challenge-response authentication works as follows: The server sends an - arbitrary "challenge" text, and prompts for a response. Protocol 2 al- - lows multiple challenges and responses; protocol 1 is restricted to just - one challenge/response. Examples of challenge-response authentication - include BSD Authentication (see login.conf(5)) and PAM (some non-OpenBSD - systems). + arbitrary "challenge" text, and prompts for a response. Protocol 2 + allows multiple challenges and responses; protocol 1 is restricted to + just one challenge/response. Examples of challenge-response authentica- + tion include BSD Authentication (see login.conf(5)) and PAM (some non- + OpenBSD systems). Finally, if other authentication methods fail, ssh prompts the user for a password. The password is sent to the remote host for checking; however, @@ -442,14 +389,14 @@ ~/.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 server spoofing or man-in-the-middle attacks, + tification ever changes, ssh warns about this and disables password + authentication to prevent server spoofing or man-in-the-middle attacks, which could otherwise be used to circumvent the encryption. The StrictHostKeyChecking option can be used to control logins to machines whose host key is not known or has changed. - 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. @@ -474,7 +421,7 @@ ter can be changed in configuration files using the EscapeChar configura- tion directive or on the command line by the -e option. - The supported escapes (assuming the default `~') are: + The supported escapes (assuming the default '~') are: ~. Disconnect. @@ -491,8 +438,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 above). It also al- - lows the cancellation of existing remote port-forwardings using + forwardings using the -L and -R options (see above). It also + allows the cancellation of existing remote port-forwardings using -KR[bind_address:]port. !command allows the user to execute a local command if the PermitLocalCommand option is enabled in ssh_config(5). Basic help is available, using the -h option. @@ -557,8 +504,8 @@ If the ForwardAgent variable is set to ``yes'' (or see the description of the -A and -a options above) and the user is using an authentication - agent, the connection to the agent is automatically forwarded to the re- - mote side. + agent, the connection to the agent is automatically forwarded to the + remote side. VERIFYING HOST KEYS When connecting to a server for the first time, a fingerprint of the @@ -570,14 +517,14 @@ If the fingerprint is already known, it can be matched and verified, and the key can be accepted. If the fingerprint is unknown, an alternative - method of verification is available: SSH fingerprints verified by DNS. - An additional resource record (RR), SSHFP, is added to a zonefile and the - connecting client is able to match the fingerprint with that of the key - presented. + method of verification is available: SSH fingerprints or certificates + verified by DNS. An additional resource record (RR), SSHFP or CERT, is + added to a zonefile and the connecting client is able to match the fin- + gerprint or certificate with that of the key presented. In this example, we are connecting a client to a server, - ``host.example.com''. The SSHFP resource records should first be added - to the zonefile for host.example.com: + ``host.example.com''. The SSHFP or CERT resource records should first be + added to the zonefile for host.example.com: $ ssh-keygen -r host.example.com. @@ -586,6 +533,10 @@ $ dig -t SSHFP host.example.com + To check that the zone is answering certificate queries: + + $ dig -t CERT host.example.com + Finally the client connects: $ ssh -o "VerifyHostKeyDNS ask" host.example.com @@ -593,19 +544,21 @@ Matching host key fingerprint found in DNS. Are you sure you want to continue connecting (yes/no)? + When host key is a X.509 certificate ``Distinguished Name'' is shown too. + See the VerifyHostKeyDNS option in ssh_config(5) for more information. SSH-BASED VIRTUAL PRIVATE NETWORKS ssh contains support for Virtual Private Network (VPN) tunnelling using - the tun(4) network pseudo-device, allowing two networks to be joined se- - curely. The sshd_config(5) configuration option PermitTunnel controls + the tun(4) network pseudo-device, allowing two networks to be joined + securely. The sshd_config(5) configuration option PermitTunnel controls whether the server supports this, and at what level (layer 2 or 3 traf- fic). - The following example would connect client network 10.0.50.0/24 with re- - mote network 10.0.99.0/24 using a point-to-point connection from 10.1.1.1 - to 10.1.1.2, provided that the SSH server running on the gateway to the - remote network, at 192.168.1.15, allows it. + The following example would connect client network 10.0.50.0/24 with + remote network 10.0.99.0/24 using a point-to-point connection from + 10.1.1.1 to 10.1.1.2, provided that the SSH server running on the gateway + to the remote network, at 192.168.1.15, allows it. On the client: @@ -639,7 +592,7 @@ X11 server. It is automatically set by ssh to point to a value of the form ``hostname:n'', where ``hostname'' indicates the host where the shell - runs, and `n' is an integer >= 1. ssh uses this + runs, and 'n' is an integer >= 1. ssh uses this special value to forward X11 connections over the secure channel. The user should normally not set DISPLAY explicitly, as that will render the X11 @@ -671,18 +624,18 @@ communicate with the agent. SSH_CONNECTION Identifies the client and server ends of the con- - nection. The variable contains four space-separat- - ed values: client IP address, client port number, - server IP address, and server port number. + nection. The variable contains four space-sepa- + rated values: client IP address, client port num- + ber, server IP address, and server port number. SSH_ORIGINAL_COMMAND This variable contains the original command line if a forced command is executed. It can be used to extract the original arguments. - SSH_TTY This is set to the name of the tty (path to the de- - vice) associated with the current shell or command. - If the current session has no tty, this variable is - not set. + SSH_TTY This is set to the name of the tty (path to the + device) associated with the current shell or com- + mand. If the current session has no tty, this + variable is not set. TZ This variable is set to indicate the present time zone if it was set when the daemon was started @@ -692,19 +645,19 @@ USER Set to the name of the user logging in. Additionally, ssh reads ~/.ssh/environment, and adds lines of the format - ``VARNAME=value'' to the environment if the file exists and users are al- - lowed to change their environment. For more information, see the + ``VARNAME=value'' to the environment if the file exists and users are + allowed to change their environment. For more information, see the PermitUserEnvironment option in sshd_config(5). FILES ~/.rhosts This file is used for host-based authentication (see above). On - some machines this file may need to be world-readable if the us- - er's home directory is on an NFS partition, because sshd(8) reads - it as root. Additionally, this file must be owned by the user, - and must not have write permissions for anyone else. The recom- - mended permission for most machines is read/write for the user, - and not accessible by others. + some machines this file may need to be world-readable if the + user's home directory is on an NFS partition, because sshd(8) + reads it as root. Additionally, this file must be owned by the + user, and must not have write permissions for anyone else. The + recommended permission for most machines is read/write for the + user, and not accessible by others. ~/.shosts This file is used in exactly the same way as .rhosts, but allows @@ -712,11 +665,20 @@ rlogin/rsh. ~/.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. This file is not highly sensitive, but the - recommended permissions are read/write for the user, and not ac- - cessible 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. This file is not highly + sensitive, but the recommended permissions are read/write for the + user, and not accessible by others. + + ~/.ssh/ca/ca-bundle.crt + ~/.ssh/ca/ca-bundle.crl + Part of user ``X.509 store''. Same as systemwide files below. + + ~/.ssh/ca/crt + ~/.ssh/ca/crl + Part of user ``X.509 store''. Same as systemwide directories + below. ~/.ssh/config This is the per-user configuration file. The file format and @@ -731,24 +693,28 @@ ~/.ssh/identity ~/.ssh/id_dsa ~/.ssh/id_rsa - Contains the private key for authentication. These files contain - sensitive data and should be readable by the user but not acces- - sible by others (read/write/execute). ssh will simply ignore a - private key file if it is accessible by others. It is possible - to specify a passphrase when generating the key which will be - used to encrypt the sensitive part of this file using 3DES. + Contains the private key for authentication. It is possible pro- + tocol 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). ssh will simply ignore a private key file + if it is accessible by others. It is possible to specify a + passphrase when generating the key which 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. These files are not - sensitive and can (but need not) be readable by anyone. + Contains the public key for authentication. Note for protocol + version 2 if an identity contain private key followed by X.509 + certificate, file must contain that certificate. These files are + not sensitive and can (but need not) be readable by anyone. ~/.ssh/known_hosts - Contains a list of host keys for all hosts the user has logged - into that are not already in the systemwide list of known host - keys. See sshd(8) for further details of the format of this - file. + Contains a list of host keys or certificates for all hosts the + user has logged into that are not already in the systemwide list + of known host keys. See sshd(8) for further details of the for- + mat of this file. ~/.ssh/rc Commands in this file are executed by ssh when the user logs in, @@ -760,10 +726,28 @@ should only be writable by root. /etc/shosts.equiv - This file is used in exactly the same way as hosts.equiv, but al- - lows host-based authentication without permitting login with + This file is used in exactly the same way as hosts.equiv, but + allows host-based authentication without permitting login with rlogin/rsh. + /etc/ssh/ca/ca-bundle.crt + /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 + /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. + /etc/ssh/ssh_config Systemwide configuration file. The file format and configuration options are described in ssh_config(5). @@ -772,18 +756,25 @@ /etc/ssh/ssh_host_dsa_key /etc/ssh/ssh_host_rsa_key These three files contain the private parts of the host keys and - are used for host-based authentication. If protocol version 1 is - used, ssh must be setuid root, since the host key is readable on- - ly by root. For protocol version 2, ssh uses ssh-keysign(8) to - access the host keys, eliminating the requirement that ssh be se- - tuid root when host-based authentication is used. By default ssh - is not setuid root. + are used for host-based authentication. It is possible files to + contain private part followed by X.509 certificate that match it + for protocol version 2 keys. If protocol version 1 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, eliminating the requirement that ssh be setuid root + when host-based authentication is used. By default ssh is not + setuid root. When a certificate is used as host key for host- + based 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/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. It should be world-readable. - See sshd(8) for further details of the format of this file. + 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. It should be world-readable. See sshd(8) for further + details of the format of this file. /etc/ssh/sshrc Commands in this file are executed by ssh when the user logs in, @@ -823,8 +814,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 4.0 September 25, 1999 13 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/ssh.1 openssh-4.5p1+x509-6.1/ssh.1 --- openssh-4.5p1/ssh.1 2006-11-04 20:31:33.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh.1 2006-11-08 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.265 2006/10/28 18:08:10 otto Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -309,6 +310,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 @@ -429,74 +432,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 ExitOnForwardFailure -.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 LocalCommand -.It LocalForward -.It LogLevel -.It MACs -.It NoHostAuthenticationForLocalhost -.It NumberOfPasswordPrompts -.It PasswordAuthentication -.It PermitLocalCommand -.It Port -.It PreferredAuthentications -.It Protocol -.It ProxyCommand -.It PubkeyAuthentication -.It RekeyLimit -.It RemoteForward -.It RhostsRSAAuthentication -.It RSAAuthentication -.It SendEnv -.It ServerAliveInterval -.It ServerAliveCountMax -.It SmartcardDevice -.It StrictHostKeyChecking -.It TCPKeepAlive -.It Tunnel -.It TunnelDevice -.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 @@ -705,7 +642,7 @@ Additionally, the server .Em must be able to verify the client's -host key (see the description of +host key or certificate (see the description of .Pa /etc/ssh/ssh_known_hosts and .Pa ~/.ssh/known_hosts , @@ -720,18 +657,18 @@ disabled if security is desired.] .Pp Public key authentication works as follows: -The scheme is based on public-key cryptography, +The scheme is based on public-key cryptography or infrastructure (PKI), using cryptosystems where encryption and decryption are done using separate keys, and it is unfeasible to derive the decryption key from the encryption key. The idea is that each user creates a public/private key pair for authentication purposes. -The server knows the public key, and only the user knows the private key. +The server knows the public key or certificate, and only the user knows the private key. .Nm implements public key authentication protocol automatically, using either the RSA or DSA algorithms. Protocol 1 is restricted to using only RSA keys, -but protocol 2 may use either. +but protocol 2 may use either or X.509 certificates. The .Sx HISTORY section of @@ -740,13 +677,13 @@ .Pp The file .Pa ~/.ssh/authorized_keys -lists the public keys that are permitted for logging in. +lists the public keys or certificates that are permitted for logging in. When the user logs in, the .Nm -program tells the server which key pair it would like to use for +program tells the server which key pair or certificate it would like to use for authentication. The client proves that it has access to the private key -and the server checks that the corresponding public key +and the server checks that the corresponding public key or certificate is authorized to accept the account. .Pp The user creates his/her key pair by running @@ -768,15 +705,26 @@ .Pa ~/.ssh/id_rsa.pub (protocol 2 RSA) in the user's home directory. -The user should then copy the public key +It is possible protocol version 2 identity file to contain +private key followed by X.509 certificate that match it. +In this case *.pub file must contain that certificate. +The user should then copy the public key or certificate to .Pa ~/.ssh/authorized_keys in his/her home directory on the remote machine. +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. The .Pa authorized_keys file corresponds to the conventional .Pa ~/.rhosts -file, and has one key +file, and has one key or certificate per line, though the lines can be very long. After this, the user can log in without giving the password. .Pp @@ -1029,16 +977,17 @@ and the key can be accepted. If the fingerprint is unknown, an alternative method of verification is available: -SSH fingerprints verified by DNS. +SSH fingerprints or certificates verified by DNS. An additional resource record (RR), -SSHFP, +SSHFP or CERT, is added to a zonefile and the connecting client is able to match the fingerprint +or certificate with that of the key presented. .Pp In this example, we are connecting a client to a server, .Dq host.example.com . -The SSHFP resource records should first be added to the zonefile for +The SSHFP or CERT resource records should first be added to the zonefile for host.example.com: .Bd -literal -offset indent $ ssh-keygen -r host.example.com. @@ -1049,6 +998,10 @@ .Pp .Dl $ dig -t SSHFP host.example.com .Pp +To check that the zone is answering certificate queries: +.Pp +.Dl $ dig -t CERT host.example.com +.Pp Finally the client connects: .Bd -literal -offset indent $ ssh -o "VerifyHostKeyDNS ask" host.example.com @@ -1057,6 +1010,10 @@ Are you sure you want to continue connecting (yes/no)? .Ed .Pp +When host key is a X.509 certificate +.Dq Distinguished Name +is shown too. +.Pp See the .Cm VerifyHostKeyDNS option in @@ -1243,13 +1200,25 @@ rlogin/rsh. .Pp .It ~/.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. This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .Pp +.It ~/.ssh/ca/ca-bundle.crt +.It ~/.ssh/ca/ca-bundle.crl +Part of user +.Dq "X.509 store" . +Same as systemwide files below. +.Pp +.It ~/.ssh/ca/crt +.It ~/.ssh/ca/crl +Part of user +.Dq "X.509 store" . +Same as systemwide directories below. +.Pp .It ~/.ssh/config This is the per-user configuration file. The file format and configuration options are described in @@ -1266,6 +1235,8 @@ .It ~/.ssh/id_dsa .It ~/.ssh/id_rsa Contains the private key for authentication. +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). @@ -1279,11 +1250,13 @@ .It ~/.ssh/id_dsa.pub .It ~/.ssh/id_rsa.pub Contains the public key for authentication. +Note for protocol version 2 if an identity contain private key +followed by X.509 certificate, file must contain that certificate. These files are not sensitive and can (but need not) be readable by anyone. .Pp .It ~/.ssh/known_hosts -Contains a list of host keys for all hosts the user has logged into +Contains a list of host keys or certificates for all hosts the user has logged into that are not already in the systemwide list of known host keys. See .Xr sshd 8 @@ -1308,6 +1281,28 @@ but allows host-based authentication without permitting login with rlogin/rsh. .Pp +.It /etc/ssh/ca/ca-bundle.crt +.It /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. +.Pp +.It /etc/ssh/ca/crt +.It /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. +.Pp .It Pa /etc/ssh/ssh_config Systemwide configuration file. The file format and configuration options are described in @@ -1318,6 +1313,9 @@ .It /etc/ssh/ssh_host_rsa_key These three files contain the private parts of the host keys and are used for host-based authentication. +It is possible files to contain private part +followed by X.509 certificate that match it +for protocol version 2 keys. If protocol version 1 is used, .Nm must be setuid root, since the host key is readable only by root. @@ -1332,12 +1330,17 @@ 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 . .Pp .It /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. It should be world-readable. See .Xr sshd 8 @@ -1427,3 +1430,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.5p1/ssh-add.0 openssh-4.5p1+x509-6.1/ssh-add.0 --- openssh-4.5p1/ssh-add.0 2006-11-07 15:07:19.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-add.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-ADD(1) OpenBSD Reference Manual SSH-ADD(1) +SSH-ADD(1) BSD General Commands Manual SSH-ADD(1) NAME - ssh-add - adds RSA or DSA identities to the authentication agent + ssh-add -- adds RSA or DSA identities to the authentication agent SYNOPSIS ssh-add [-cDdLlXx] [-t life] [file ...] @@ -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 4.0 September 25, 1999 2 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/ssh-add.1 openssh-4.5p1+x509-6.1/ssh-add.1 --- openssh-4.5p1/ssh-add.1 2005-05-26 05:04:02.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-add.1 2006-11-08 09:06:00.000000000 +0200 @@ -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.5p1/ssh-add.c openssh-4.5p1+x509-6.1/ssh-add.c --- openssh-4.5p1/ssh-add.c 2006-09-01 08:38:37.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-add.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.89 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -13,6 +13,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 @@ -61,6 +63,8 @@ #include "authfile.h" #include "pathnames.h" #include "misc.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" /* argv0 */ extern char *__progname; @@ -250,9 +254,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); @@ -342,6 +357,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.5p1/ssh-agent.0 openssh-4.5p1+x509-6.1/ssh-agent.0 --- openssh-4.5p1/ssh-agent.0 2006-11-07 15:07:20.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-agent.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-AGENT(1) OpenBSD Reference Manual SSH-AGENT(1) +SSH-AGENT(1) BSD General Commands Manual SSH-AGENT(1) NAME - ssh-agent - authentication agent + ssh-agent -- authentication agent SYNOPSIS ssh-agent [-a bind_address] [-c | -s] [-t life] [-d] [command [args ...]] @@ -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-XXXXXXXXXX/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. @@ -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,11 +94,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. /tmp/ssh-XXXXXXXXXX/agent. Unix-domain sockets used to contain the connection to the authen- @@ -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 4.0 September 25, 1999 2 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/ssh-agent.1 openssh-4.5p1+x509-6.1/ssh-agent.1 --- openssh-4.5p1/ssh-agent.1 2006-07-24 07:04:53.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-agent.1 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.44 2006/07/18 08:03:09 jmc 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 @@ -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,8 +186,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. .It Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt Unix-domain sockets used to contain the connection to the authentication agent. @@ -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.5p1/ssh-agent.c openssh-4.5p1+x509-6.1/ssh-agent.c --- openssh-4.5p1/ssh-agent.c 2006-10-23 20:01:16.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-agent.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.153 2006/10/06 02:29:19 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -12,6 +12,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 @@ -73,6 +75,8 @@ #include "authfd.h" #include "compat.h" #include "log.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" #include "misc.h" #ifdef SMARTCARD @@ -173,6 +177,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) @@ -181,7 +204,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); @@ -326,8 +349,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); @@ -472,6 +499,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); @@ -480,6 +508,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); @@ -495,10 +524,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) { @@ -1043,6 +1091,7 @@ #endif SSLeay_add_all_algorithms(); + fill_default_xkalg(); __progname = ssh_get_progname(av[0]); init_rng(); diff -ruN openssh-4.5p1/ssh.c openssh-4.5p1+x509-6.1/ssh.c --- openssh-4.5p1/ssh.c 2006-10-23 20:01:16.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.294 2006/10/06 02:29:19 djm Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -19,6 +19,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: @@ -72,6 +75,10 @@ #include #include +#ifdef LDAP_ENABLED +/* OpenSSL extension defined in x509_by_ldap.c */ +extern void ERR_load_X509byLDAP_strings(void); +#endif #include "xmalloc.h" #include "ssh.h" @@ -107,6 +114,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; @@ -221,6 +231,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 @@ -555,6 +566,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.5p1/ssh_config openssh-4.5p1+x509-6.1/ssh_config --- openssh-4.5p1/ssh_config 2006-06-13 06:01:10.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh_config 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -# $OpenBSD: ssh_config,v 1.22 2006/05/29 12:56:33 dtucker Exp $ +# $OpenBSD$ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for @@ -39,6 +39,17 @@ # 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 # Tunnel no # TunnelDevice any:any # PermitLocalCommand no diff -ruN openssh-4.5p1/ssh_config.0 openssh-4.5p1+x509-6.1/ssh_config.0 --- openssh-4.5p1/ssh_config.0 2006-11-07 15:07:30.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh_config.0 2007-10-25 19:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH_CONFIG(5) OpenBSD Programmer's Manual SSH_CONFIG(5) +SSH_CONFIG(5) BSD File Formats Manual SSH_CONFIG(5) NAME - ssh_config - OpenSSH SSH client configuration files + ssh_config -- OpenSSH SSH client configuration files SYNOPSIS ~/.ssh/config @@ -27,20 +27,20 @@ The configuration file has the following format: - Empty lines and lines starting with `#' are comments. Otherwise a line + Empty lines and lines starting with '#' are comments. Otherwise a line is of the format ``keyword arguments''. Configuration options may be - separated by whitespace or optional whitespace and exactly one `='; the + separated by whitespace or optional whitespace and exactly one '='; the latter format is useful to avoid the need to quote whitespace when speci- - fying configuration options using the ssh, scp, and sftp -o option. Ar- - guments may optionally be enclosed in double quotes (") in order to rep- - resent arguments containing spaces. + fying configuration options using the ssh, scp, and sftp -o option. + Arguments may optionally be enclosed in double quotes (") in order to + represent arguments containing spaces. The possible keywords and their meanings are as follows (note that key- words are case-insensitive and arguments are case-sensitive): Host Restricts the following declarations (up to the next Host key- word) to be only for those hosts that match one of the patterns - given after the keyword. A single `*' as a pattern can be used + given after the keyword. A single '*' as a pattern can be used to provide global defaults for all hosts. The host is the hostname argument given on the command line (i.e. the name is not converted to a canonicalized host name before matching). @@ -48,9 +48,21 @@ See PATTERNS for more information on patterns. AddressFamily - Specifies which address family to use when connecting. Valid ar- - guments are ``any'', ``inet'' (use IPv4 only), or ``inet6'' (use - IPv6 only). + 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: + sslserver | SSL server | SSL_server | server + only SSL-server purpose + any | Any Purpose | Any_Purpose | AnyPurpose + allow any purpose + skip | '' (empty) + do not check purpose + The default is ``sslserver''. BatchMode If set to ``yes'', passphrase/password querying will be disabled. @@ -59,11 +71,47 @@ ``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 '=' ! LDAP initialization method may + require URL to be escaped, i.e. use '%2C' instead of ',' (comma). + Escaped URL don't depend from LDAP initialization method. + + 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 @@ -115,15 +163,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 @@ -156,9 +204,9 @@ ControlPath Specify the path to the control socket used for connection shar- ing as described in the ControlMaster section above or the string - ``none'' to disable connection sharing. In the path, `%l' will - be substituted by the local host name, `%h' will be substituted - by the target host name, `%p' the port, and `%r' by the remote + ``none'' to disable connection sharing. In the path, '%l' will + be substituted by the local host name, '%h' will be substituted + by the target host name, '%p' the port, and '%r' by the remote login username. It is recommended that any ControlPath used for opportunistic connection sharing include at least %h, %p, and %r. This ensures that shared connections are uniquely identified. @@ -170,12 +218,12 @@ The argument must be [bind_address:]port. IPv6 addresses can be specified by enclosing addresses in square brackets or by using - an alternative syntax: [bind_address/]port. By default, the lo- - cal port is bound in accordance with the GatewayPorts setting. + an alternative syntax: [bind_address/]port. By default, the + local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connec- tion 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 `*' indicates that the port should be + while an empty address or '*' indicates that the port should be available from all interfaces. Currently the SOCKS4 and SOCKS5 protocols are supported, and @@ -192,9 +240,9 @@ for more information. EscapeChar - Sets the escape character (default: `~'). The escape character + Sets the escape character (default: '~'). The escape character can also be set on the command line. The argument should be a - single character, `^' followed by a letter, or ``none'' to dis- + single character, '^' followed by a letter, or ``none'' to dis- able the escape character entirely (making the connection trans- parent for binary data). @@ -218,9 +266,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 @@ -265,8 +313,8 @@ 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(1) should hash host names and addresses when @@ -280,19 +328,21 @@ 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 - name when looking up or saving the host key in the host key - database files. This option is useful for tunneling SSH connec- - tions or for multiple servers running on a single host. + name when looking up or saving the host key in the host key data- + base files. This option is useful for tunneling SSH connections + or for multiple servers running on a single host. HostName Specifies the real host name to log into. This can be used to @@ -313,20 +363,22 @@ 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. + 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 or one of the following escape characters: `%d' (local - user's home directory), `%u' (local user name), `%l' (local host - name), `%h' (remote host name) or `%r' (remote user name). + directory or one of the following escape characters: '%d' (local + user's home directory), '%u' (local user name), '%l' (local host + name), '%h' (remote host name) or '%r' (remote user name). It is possible to have multiple identity files specified in con- figuration files; all these identities will be tried in sequence. 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. The methods available vary depending on what the server supports. For an OpenSSH server, it may be zero or more of: ``bsdauth'', ``pam'', @@ -335,8 +387,8 @@ LocalCommand Specifies a command to execute on the local machine after suc- cessfully connecting to the server. The command string extends - to the end of the line, and is executed with /bin/sh. This di- - rective is ignored unless PermitLocalCommand has been enabled. + to the end of the line, and is executed with /bin/sh. This + directive is ignored unless PermitLocalCommand has been enabled. LocalForward Specifies that a TCP port on the local machine be forwarded over @@ -349,11 +401,11 @@ can be given on the command line. Only the superuser can forward privileged ports. By default, the local port is bound in accor- dance with the GatewayPorts setting. However, an explicit - bind_address may be used to bind the connection to a specific ad- - dress. The bind_address of ``localhost'' indicates that the lis- - tening port be bound for local use only, while an empty address - or `*' indicates that the port should be available from all in- - terfaces. + 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 '*' indicates that the port should be available from + all interfaces. LogLevel Gives the verbosity level that is used when logging messages from @@ -362,20 +414,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 @@ -387,23 +444,23 @@ ``yes''. PermitLocalCommand - Allow local command execution via the LocalCommand option or us- - ing the !command escape sequence in ssh(1). The argument must be - ``yes'' or ``no''. The default is ``no''. + Allow local command execution via the LocalCommand option or + using the !command escape sequence in ssh(1). The argument must + be ``yes'' or ``no''. The default is ``no''. - Port Specifies the port number to connect on the remote host. The de- - fault is 22. + Port Specifies the port number to connect on the remote host. The + default 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: ``gssapi-with-mic,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: ``gssapi-with-mic, + hostbased, publickey, keyboard-interactive, password''. Protocol Specifies the protocol versions ssh(1) should support in order of - preference. The possible values are `1' and `2'. Multiple ver- + preference. The possible values are '1' and '2'. Multiple ver- sions must be comma-separated. The default is ``2,1''. This means that ssh tries version 2 and falls back to version 1 if version 2 is not available. @@ -411,16 +468,16 @@ ProxyCommand Specifies the command to use to connect to the server. The com- mand string extends to the end of the line, and is executed with - /bin/sh. In the command string, `%h' will be substituted by the - host name to connect and `%p' by the port. The command can be + /bin/sh. In the command string, '%h' will be substituted by the + host name to connect and '%p' by the port. The command can be basically anything, and should read from its standard input and 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 @@ -428,18 +485,28 @@ 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 ``yes''. This option applies to protocol version 2 only. RekeyLimit - Specifies the maximum amount of data that may be transmitted be- - fore the session key is renegotiated. The argument is the number - of bytes, with an optional suffix of `K', `M', or `G' to indicate - Kilobytes, Megabytes, or Gigabytes, respectively. The default is - between `1G' and `4G', depending on the cipher. This option ap- - plies to protocol version 2 only. + Specifies the maximum amount of data that may be transmitted + before the session key is renegotiated. The argument is the num- + ber of bytes, with an optional suffix of 'K', 'M', or 'G' to + indicate Kilobytes, Megabytes, or Gigabytes, respectively. The + default is between '1G' and '4G', depending on the cipher. This + option applies to protocol version 2 only. RemoteForward Specifies that a TCP port on the remote machine be forwarded over @@ -453,7 +520,7 @@ privileged ports. If the bind_address is not specified, the default is to only bind - to loopback addresses. If the bind_address is `*' or an empty + to loopback addresses. If the bind_address is '*' or an empty string, then the forwarding is requested to listen on all inter- faces. Specifying a remote bind_address will only succeed if the server's GatewayPorts option is enabled (see sshd_config(5)). @@ -479,16 +546,16 @@ to AcceptEnv in sshd_config(5) for how to configure the server. Variables are specified by name, which may contain wildcard char- acters. Multiple environment variables may be separated by - whitespace or spread across multiple SendEnv directives. The de- - fault is not to send any environment variables. + whitespace or spread across multiple SendEnv directives. The + default is not to send any environment variables. See PATTERNS for more information on patterns. ServerAliveCountMax Sets the number of server alive messages (see below) which may be sent without ssh(1) receiving any messages back from the server. - If this threshold is reached while server alive messages are be- - ing sent, ssh will disconnect from the server, terminating the + If this threshold is reached while server alive messages are + being sent, ssh will disconnect from the server, terminating the session. It is important to note that the use of server alive messages is very different from TCPKeepAlive (below). The server alive messages are sent through the encrypted channel and there- @@ -513,9 +580,9 @@ SmartcardDevice Specifies which smartcard device to use. The argument to this keyword is the device ssh(1) should use to communicate with a - smartcard used for storing the user's private RSA key. By de- - fault, no device is specified and smartcard support is not acti- - vated. + smartcard used for storing the user's private RSA key. By + default, no device is specified and smartcard support is not + activated. StrictHostKeyChecking If this flag is set to ``yes'', ssh(1) will never automatically @@ -523,23 +590,23 @@ nect to hosts whose host key has changed. This provides maximum protection against trojan horse attacks, though it can be annoy- ing when the /etc/ssh/ssh_known_hosts file is poorly maintained - or when connections to new hosts are frequently made. This op- - tion forces the user to manually add all new hosts. If this flag - is set to ``no'', ssh will automatically add new host keys to the - user known hosts files. If this flag is set to ``ask'', new host - keys will be added to the user known host files only after the - user has confirmed that is what they really want to do, and ssh - will refuse to connect to hosts whose host key has changed. The - host keys of known hosts will be verified automatically in all - cases. The argument must be ``yes'', ``no'', or ``ask''. The - default is ``ask''. + or when connections to new hosts are frequently made. This + option forces the user to manually add all new hosts. If this + flag is set to ``no'', ssh will automatically add new host keys + to the user known hosts files. If this flag is set to ``ask'', + new host keys will be added to the user known host files only + after the user has confirmed that is what they really want to do, + and ssh will refuse to connect to hosts whose host key has + changed. The host keys of known hosts will be verified automati- + cally in all cases. The argument must be ``yes'', ``no'', or + ``ask''. The default is ``ask''. TCPKeepAlive Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, - this means that connections will die if the route is down tem- - porarily, and some people find it annoying. + this means that connections will die if the route is down tempo- + rarily, and some people find it annoying. The default is ``yes'' (to send TCP keepalive messages), and the client will notice if the network goes down or the remote host @@ -548,11 +615,11 @@ To disable TCP keepalive messages, the value should be set to ``no''. - Tunnel Request tun(4) device forwarding between the client and the serv- - er. The argument must be ``yes'', ``point-to-point'' (layer 3), - ``ethernet'' (layer 2), or ``no''. Specifying ``yes'' requests - the default tunnel mode, which is ``point-to-point''. The de- - fault is ``no''. + Tunnel Request tun(4) device forwarding between the client and the + server. The argument must be ``yes'', ``point-to-point'' (layer + 3), ``ethernet'' (layer 2), or ``no''. Specifying ``yes'' + requests the default tunnel mode, which is ``point-to-point''. + The default is ``no''. TunnelDevice Specifies the tun(4) devices to open on the client (local_tun) @@ -575,31 +642,94 @@ 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: + 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. + 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. See also VERIFYING HOST KEYS in ssh(1). + 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 is /usr/X11R6/bin/xauth. PATTERNS - A pattern consists of zero or more non-whitespace characters, `*' (a - wildcard that matches zero or more characters), or `?' (a wildcard that + A pattern consists of zero or more non-whitespace characters, '*' (a + wildcard that matches zero or more characters), or '?' (a wildcard that matches exactly one character). For example, to specify a set of decla- rations for any host in the ``.co.uk'' set of domains, the following pat- tern could be used: @@ -613,18 +743,19 @@ A pattern-list is a comma-separated list of patterns. Patterns within pattern-lists may be negated by preceding them with an exclamation mark - (`!'). For example, to allow a key to be used from anywhere within an - organisation except from the ``dialup'' pool, the following entry (in au- - thorized_keys) could be used: + ('!'). For example, to allow a key to be used from anywhere within an + organisation except from the ``dialup'' pool, the following entry (in + authorized_keys) could be used: from="!*.dialup.example.com,*.example.com" 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 @@ -640,6 +771,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 4.0 September 25, 1999 10 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/ssh_config.5 openssh-4.5p1+x509-6.1/ssh_config.5 --- openssh-4.5p1/ssh_config.5 2006-08-05 04:34:51.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh_config.5 2007-10-25 19: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.97 2006/07/27 08:00:50 jmc Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSH_CONFIG 5 .Os @@ -125,6 +126,20 @@ (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 -tag -width Ds -compact +.It Cm sslserver | Cm SSL server | Cm SSL_server | Cm server +only SSL-server purpose +.It Cm any | Cm Any Purpose | Cm Any_Purpose | Cm AnyPurpose +allow any purpose +.It Cm skip | Cm '' Li (empty) +do not check purpose +.El +The default is +.Dq sslserver . .It Cm BatchMode If set to .Dq yes , @@ -145,6 +160,60 @@ .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 = +! +LDAP initialization method may require URL to be escaped, i.e. use +.Sq %2C +instead of +.Sq \&, +(comma). +Escaped URL don't depend from LDAP initialization method. +.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 @@ -516,8 +585,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 @@ -558,6 +631,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. .Pp @@ -644,6 +719,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 @@ -746,6 +830,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 @@ -1003,12 +1106,99 @@ 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 -tag -offset indent -compact +.It none +do not use OCSP to validate certificates; +.It ocspcert +validate only certificates that specify +.Sq "OCSP Service Locator" +URL; +.It 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 , @@ -1035,6 +1225,48 @@ .Sx VERIFYING HOST KEYS in .Xr ssh 1 . +.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 @@ -1103,3 +1335,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.5p1/sshconnect2.c openssh-4.5p1+x509-6.1/sshconnect2.c --- openssh-4.5p1/sshconnect2.c 2006-09-01 08:38:37.000000000 +0300 +++ openssh-4.5p1+x509-6.1/sshconnect2.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,6 +1,7 @@ -/* $OpenBSD: sshconnect2.c,v 1.162 2006/08/30 00:06:51 dtucker Exp $ */ +/* $OpenBSD$ */ /* * 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 @@ -849,6 +850,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); @@ -1024,6 +1026,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; @@ -1101,11 +1104,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++) @@ -1119,13 +1181,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.5p1/sshconnect.c openssh-4.5p1+x509-6.1/sshconnect.c --- openssh-4.5p1/sshconnect.c 2006-10-23 20:02:24.000000000 +0300 +++ openssh-4.5p1+x509-6.1/sshconnect.c 2007-10-25 19:06:01.000000000 +0300 @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.200 2006/10/10 10:12:45 markus Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -11,6 +11,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-2007 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" @@ -55,6 +78,7 @@ #include "readconf.h" #include "atomicio.h" #include "misc.h" +#include "ssh-x509.h" #include "dns.h" #include "version.h" @@ -545,6 +569,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 @@ -720,13 +745,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", + 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; @@ -768,7 +807,7 @@ if (readonly == ROQUIET) goto fail; 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) @@ -915,9 +954,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); } } } @@ -1019,7 +1064,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++) { @@ -1064,6 +1110,11 @@ 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 '%s'.", subject); + xfree(subject); + } error("Please contact your system administrator."); xfree(fp); diff -ruN openssh-4.5p1/sshd.0 openssh-4.5p1+x509-6.1/sshd.0 --- openssh-4.5p1/sshd.0 2006-11-07 15:07:24.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sshd.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSHD(8) OpenBSD System Manager's Manual SSHD(8) +SSHD(8) BSD System Manager's Manual SSHD(8) NAME - sshd - OpenSSH SSH daemon + sshd -- OpenSSH SSH daemon SYNOPSIS sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time] @@ -39,8 +39,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. @@ -51,10 +51,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 @@ -63,13 +63,15 @@ /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) + 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 @@ -78,14 +80,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 @@ -94,8 +96,8 @@ when a command-line port is specified. Ports specified using the ListenAddress option override command-line ports. - -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 @@ -110,18 +112,19 @@ 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. AUTHENTICATION The OpenSSH SSH daemon supports SSH protocols 1 and 2. Both protocols - are supported by default, though this can be changed via the Protocol op- - tion in sshd_config(5). Protocol 2 supports both RSA and DSA keys; pro- - tocol 1 only supports RSA keys. For both protocols, each host has a - host-specific key, normally 2048 bits, used to identify the host. + are supported by default, though this can be changed via the Protocol + option in sshd_config(5). Protocol 2 supports RSA, DSA keys and X.509 + certificates; protocol 1 only supports RSA keys. For both protocols, + each host has a host-specific key, normally 2048 bits, or X.509 certifi- + cate used to identify the host. Forward security for protocol 1 is provided through an additional server key, normally 768 bits, generated when the server starts. This key is @@ -154,18 +157,18 @@ that it is accessible. An account is not accessible if it is locked, listed in DenyUsers or its group is listed in DenyGroups . The defini- tion of a locked account is system dependant. Some platforms have their - own account database (eg AIX) and some modify the passwd field ( `*LK*' - on Solaris and UnixWare, `*' on HP-UX, containing `Nologin' on Tru64, a - leading `*LOCKED*' on FreeBSD and a leading `!!' on Linux). If there is - a requirement to disable password authentication for the account while + own account database (eg AIX) and some modify the passwd field ( '*LK*' + on Solaris and UnixWare, '*' on HP-UX, containing 'Nologin' on Tru64, a + leading '*LOCKED*' on FreeBSD and a leading '!' on Linux). If there is a + requirement to disable password authentication for the account while allowing still public-key, then the passwd field should be set to some- - thing other than these values (eg `NP' or `*NP*' ). + thing other than these values (eg 'NP' or '*NP*' ). If the client successfully authenticates itself, a dialog for preparing the session is entered. At this time the client may request things like allocating a pseudo-tty, forwarding X11 connections, forwarding TCP con- - nections, or forwarding the authentication agent connection over the se- - cure channel. + nections, or forwarding the authentication agent connection over the + secure channel. After this, the client either requests a shell or execution of a command. The sides then enter session mode. In this mode, either side may send @@ -237,20 +240,30 @@ AUTHORIZED_KEYS FILE FORMAT AuthorizedKeysFile specifies the file containing public keys for public key authentication; if none is specified, the default is - ~/.ssh/authorized_keys. Each line of the file contains one key (empty - lines and lines starting with a `#' are ignored as comments). Protocol 1 - public keys consist of the following space-separated fields: options, - bits, exponent, modulus, comment. Protocol 2 public key consist of: op- - tions, keytype, base64-encoded key, comment. The options field is op- - tional; its presence is determined by whether the line starts with a num- - ber or not (the options field never starts with a number). The bits, ex- - ponent, modulus, and comment fields give the RSA key for protocol version - 1; the comment 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''. + ~/.ssh/authorized_keys. It is posible for protocol version 2 to contain + X.509 certificates or certificates ``Distinguished Name''. Each line of + the file contains one key (empty lines and lines starting with a '#' are + ignored as comments). Protocol 1 public keys consist of the following + space-separated fields: options, bits, exponent, modulus, comment. Pro- + tocol 2 public key consist of: options, keytype, base64-encoded key, com- + ment. The options field is optional; its presence is determined by + whether the line starts with a number or not (the options field never + starts with a number). The bits, exponent, modulus, and comment fields + give the RSA key for protocol version 1; the comment 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''. 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 Subject 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. @@ -268,16 +281,16 @@ 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 and/or X11 forwarding unless they are - explicitly prohibited. The command originally supplied by the - client is available in the SSH_ORIGINAL_COMMAND environment vari- - able. Note that this option applies to shell, command or subsys- - tem 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 and/or X11 forwarding unless + they are explicitly prohibited. The command originally supplied + by the client is available in the SSH_ORIGINAL_COMMAND environ- + ment variable. 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 @@ -290,12 +303,12 @@ from="pattern-list" Specifies that in addition to public key authentication, the canonical name of the remote host must be present in the comma- - separated list of patterns. The purpose of this option is to op- - tionally increase security: public key authentication by itself + separated list of patterns. 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); however, if somebody somehow steals the key, the key per- - mits an intruder to log in from anywhere in the world. This ad- - ditional option makes using a stolen key more difficult (name + mits 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). @@ -321,8 +334,8 @@ 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. tunnel="n" Force a tun(4) device on the server. Without this option, the @@ -339,39 +352,41 @@ AAAAC3...51R== example.net permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss AAAAB5...21S== + x509v3-sign-dss subject=/C=XX/ST=World/O=OpenSSH Test Team... tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...== jane@example.net 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. - Hostnames is a comma-separated list of patterns (`*' and `?' act as wild- + Hostnames is a comma-separated list of patterns ('*' and '?' act as wild- 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. A - hostname or address may optionally be enclosed within `[' and `]' brack- - ets then followed by `:' and a non-standard port number. + 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 + accepted (by that line) even if it matched another pattern on the line. + A hostname or address may optionally be enclosed within '[' and ']' + brackets then followed by ':' and a non-standard port number. 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; they can be obtained, for example, from /etc/ssh/ssh_host_key.pub. The optional comment field continues to the end of the line, and is not used. - Lines starting with `#' and empty lines are ignored as comments. + Lines starting with '#' and empty lines are ignored as comments. When performing host authentication, authentication is accepted if any matching line has the proper key. It is thus permissible (but not recom- @@ -391,6 +406,7 @@ # Comments allowed at start of line closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....= + x509host x509v3-sign-rsa Subject:/C=XX..... # A hashed hostname |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa AAAA1234.....= @@ -398,9 +414,9 @@ FILES ~/.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. ~/.rhosts This file is used for host-based authentication (see ssh(1) for @@ -417,33 +433,34 @@ rlogin/rsh. ~/.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 above. The - content of the 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), certificates or certificates + ``Distinguished Names'' (recommended) that can be used for log- + ging in as this user. The format of this file is described + above. The content of the file is not highly sensitive, but the + recommended permissions are read/write for the user, and not + accessible by others. If this file, the ~/.ssh directory, or the user's home directory are writable by other users, then the file could be modified or - replaced by unauthorized users. In this case, sshd will not al- - low it to be used unless the StrictModes option has been set to + replaced by unauthorized users. In this case, sshd will not + allow it to be used unless the StrictModes option has been set to ``no''. The recommended permissions can be set by executing ``chmod go-w ~/ ~/.ssh ~/.ssh/authorized_keys''. ~/.ssh/environment This file is read into the environment at login (if it exists). It can only contain empty lines, comment lines (that start with - `#'), and assignment lines of the form name=value. The file + '#'), and assignment lines of the form name=value. The file should be writable only by the user; it need not be readable by anyone else. Environment processing is disabled by default and is controlled via the PermitUserEnvironment option. ~/.ssh/known_hosts - Contains a list of host keys for all hosts the user has logged - into that are not already in the systemwide list of known host - keys. The format of this file is described above. This file - should be writable only by root/the owner and can, but need not - be, world-readable. + Contains a list of host keys or certificates for all hosts the + user has logged into that are not already in the systemwide list + of known host keys. The format of this file is described above. + This file should be writable only by root/the owner and can, but + need not be, world-readable. ~/.ssh/rc Contains initialization routines to be run before the user's home @@ -452,8 +469,8 @@ /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). /etc/hosts.equiv This file is for host-based authentication (see ssh(1)). It @@ -473,34 +490,54 @@ world-readable. /etc/shosts.equiv - This file is used in exactly the same way as hosts.equiv, but al- - lows host-based authentication without permitting login with + This file is used in exactly the same way as hosts.equiv, but + allows host-based authentication without permitting login with rlogin/rsh. + /etc/ssh/ca/ca-bundle.crt + /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 + /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/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. The format of this file is de- - scribed above. This file should be writable only by root/the - owner and should be world-readable. + by the system administrator to contain the public host keys or + certificates of all machines in the organization. The format of + this file is described above. This file should be writable only + by root/the owner and should be world-readable. /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 - these files are 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 these files are + 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/ssh/sshd_config Contains configuration data for sshd. The file format and con- @@ -535,10 +572,11 @@ 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. CAVEATS System security is not improved unless rshd, rlogind, and rexecd are dis- abled (thus completely disabling rlogin and rsh into the machine). -OpenBSD 4.0 September 25, 1999 9 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/sshd.8 openssh-4.5p1+x509-6.1/sshd.8 --- openssh-4.5p1/sshd.8 2006-08-30 04:07:01.000000000 +0300 +++ openssh-4.5p1+x509-6.1/sshd.8 2006-11-08 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.234 2006/08/21 08:15:57 dtucker Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -144,6 +145,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 @@ -234,11 +237,12 @@ .Cm Protocol option in .Xr sshd_config 5 . -Protocol 2 supports both RSA and DSA keys; +Protocol 2 supports RSA, DSA keys and X.509 certificates; protocol 1 only supports RSA keys. For both protocols, each host has a host-specific key, normally 2048 bits, +or X.509 certificate used to identify the host. .Pp Forward security for protocol 1 is provided through @@ -299,7 +303,7 @@ a leading .Ql \&*LOCKED\&* on FreeBSD and a leading -.Ql \&!! +.Ql \&! on Linux). If there is a requirement to disable password authentication for the account while allowing still public-key, then the passwd field should be set to something other than these values (eg @@ -424,6 +428,9 @@ public key authentication; if none is specified, the default is .Pa ~/.ssh/authorized_keys . +It is posible for protocol version 2 to contain X.509 certificates +or certificates +.Dq "Distinguished Name" . Each line of the file contains one key (empty lines and lines starting with a .Ql # @@ -444,6 +451,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 @@ -560,6 +598,7 @@ AAAAC3...51R== example.net permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss AAAAB5...21S== +x509v3-sign-dss subject=/C=XX/ST=World/O=OpenSSH Test Team... tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...== jane@example.net .Ed @@ -568,7 +607,9 @@ .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, @@ -639,6 +680,7 @@ # Comments allowed at start of line closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....= +x509host x509v3-sign-rsa Subject:/C=XX..... # A hashed hostname |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa AAAA1234.....= @@ -679,7 +721,10 @@ rlogin/rsh. .Pp .It ~/.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), certificates or certificates +.Dq "Distinguished Names +(recommended) +that can be used for logging in as this user. The format of this file is described above. The content of the file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. @@ -711,7 +756,7 @@ option. .Pp .It ~/.ssh/known_hosts -Contains a list of host keys for all hosts the user has logged into +Contains a list of host keys or certificates for all hosts the user has logged into that are not already in the systemwide list of known host keys. The format of this file is described above. This file should be writable only by root/the owner and @@ -758,10 +803,28 @@ but allows host-based authentication without permitting login with rlogin/rsh. .Pp +.It /etc/ssh/ca/ca-bundle.crt +.It /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. +.Pp +.It /etc/ssh/ca/crt +.It /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. +.Pp .It /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 +system administrator to contain the public host keys or certificates of all machines in the organization. The format of this file is described above. This file should be writable only by root/the owner and @@ -771,6 +834,9 @@ .It /etc/ssh/ssh_host_dsa_key .It /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 @@ -784,6 +850,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. @@ -844,6 +912,7 @@ 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. .Sh CAVEATS System security is not improved unless .Nm rshd , diff -ruN openssh-4.5p1/sshd.c openssh-4.5p1+x509-6.1/sshd.c --- openssh-4.5p1/sshd.c 2006-11-07 14:14:42.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sshd.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.348 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -21,6 +21,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: @@ -116,6 +119,7 @@ #include "monitor_wrap.h" #include "monitor_fdpass.h" #include "version.h" +#include "ssh-xkalg.h" #ifdef LIBWRAP #include @@ -136,6 +140,9 @@ extern char *__progname; +/* ssh-x509.c needs this */ +extern int (*pssh_x509cert_check)(X509 *cert); + /* Server configuration options. */ ServerOptions options; @@ -727,6 +734,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); @@ -1241,6 +1252,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; @@ -1466,6 +1478,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.5p1/sshd_config openssh-4.5p1+x509-6.1/sshd_config --- openssh-4.5p1/sshd_config 2006-07-24 07:06:47.000000000 +0300 +++ openssh-4.5p1+x509-6.1/sshd_config 2007-10-25 19:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.74 2006/07/19 13:07:10 dtucker Exp $ +# $OpenBSD$ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -22,6 +22,72 @@ #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 = ! +# LDAP initialization may require URL to be escaped, i.e. +# use %2C instead of ,(comma). Escaped URL don't depend from +# LDAP initialization method. +# Example: +# CAldapURL ldap://localhost:389/dc%3Dexample%2Cdc%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.5p1/sshd_config.0 openssh-4.5p1+x509-6.1/sshd_config.0 --- openssh-4.5p1/sshd_config.0 2006-11-07 15:07:28.000000000 +0200 +++ openssh-4.5p1+x509-6.1/sshd_config.0 2007-10-25 19:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSHD_CONFIG(5) OpenBSD Programmer's Manual SSHD_CONFIG(5) +SSHD_CONFIG(5) BSD File Formats Manual SSHD_CONFIG(5) NAME - sshd_config - OpenSSH SSH daemon configuration file + sshd_config -- OpenSSH SSH daemon configuration file SYNOPSIS /etc/ssh/sshd_config @@ -9,7 +9,7 @@ DESCRIPTION sshd(8) reads configuration data from /etc/ssh/sshd_config (or the file specified with -f on the command line). The file contains keyword-argu- - ment pairs, one per line. Lines starting with `#' and empty lines are + ment pairs, one per line. Lines starting with '#' and empty lines are interpreted as comments. Arguments may optionally be enclosed in double quotes (") in order to represent arguments containing spaces. @@ -21,8 +21,8 @@ copied into the session's environ(7). See SendEnv in ssh_config(5) for how to configure the client. Note that envi- ronment passing is only supported for protocol 2. Variables are - specified by name, which may contain the wildcard characters `*' - and `?'. Multiple environment variables may be separated by + specified by name, which may contain the wildcard characters '*' + and '?'. Multiple environment variables may be separated by whitespace or spread across multiple AcceptEnv directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be @@ -34,6 +34,18 @@ 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: + sslclient | SSL client | SSL_client | client + only SSL-client purpose + any | Any Purpose | Any_Purpose | AnyPurpose + allow any purpose + skip | '' (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 @@ -48,17 +60,17 @@ 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. Only user names are + separated by spaces. If specified, login is allowed only for + user names that match one of 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 US- - ER@HOST then USER and HOST are separately checked, restricting + 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. The allow/deny directives are processed in the following order: DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups. @@ -70,8 +82,8 @@ for user authentication. AuthorizedKeysFile may contain tokens of the form %T which are substituted during connection setup. 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. + '%', %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''. @@ -82,6 +94,43 @@ 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 '=' ! LDAP ini- + tialization method may require URL to be escaped, i.e. use '%2C' + instead of ',' (comma). Escaped URL don't depend from LDAP ini- + tialization method. + + 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 @@ -102,8 +151,8 @@ ClientAliveCountMax Sets the number of client alive messages (see below) which may be sent without sshd(8) 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- @@ -135,8 +184,8 @@ separated by spaces. Login is disallowed for users whose primary group or supplementary group list matches one of the patterns. Only group names are valid; a numerical group ID is not recog- - nized. By default, login is allowed for all groups. The al- - low/deny directives are processed in the following order: + nized. By default, login is allowed for all groups. The + allow/deny directives are processed in the following order: DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups. See PATTERNS in ssh_config(5) for more information on patterns. @@ -156,8 +205,8 @@ ForceCommand Forces the execution of the command specified by ForceCommand, - ignoring any command supplied by the client. The command is in- - voked by using the user's login shell with the -c option. This + ignoring any command supplied by the client. The command is + invoked by using the user's login shell with the -c option. This applies to shell, command, or subsystem execution. It is most useful inside a Match block. The command originally supplied by the client is available in the SSH_ORIGINAL_COMMAND environment @@ -171,8 +220,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''. @@ -186,16 +235,24 @@ 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 (host-based authentication). This option is similar to RhostsRSAAuthentication and applies to protocol version 2 only. The default is ``no''. HostbasedUsesNameFromPacketOnly - Specifies whether or not the server will attempt to perform a re- - verse name lookup when matching the name in the ~/.shosts, + Specifies whether or not the server will attempt to perform a + reverse name lookup when matching the name in the ~/.shosts, ~/.rhosts, and /etc/hosts.equiv files during HostbasedAuthentication. A setting of ``yes'' means that sshd(8) uses the name supplied by the client rather than attempting to @@ -209,14 +266,16 @@ tocol version 2. Note that sshd(8) 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. + or ``rsa'' are used for version 2 of the SSH protocol. For ver- + sion 2 is possible file to contain private key followed by X.509 + certificate 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(8) should ignore the user's @@ -244,6 +303,21 @@ Specifies whether to automatically destroy the user's ticket cache file on logout. The 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 @@ -281,20 +355,26 @@ 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''. Match Introduces a conditional block. If all of the criteria on the Match line are satisfied, the keywords on the following lines - override those set in the global section of the config file, un- - til either another Match line or the end of the file. The argu- - ments to Match are one or more criteria-pattern pairs. The + override those set in the global section of the config file, + until either another Match line or the end of the file. The + arguments to Match are one or more criteria-pattern pairs. The available criteria are User, Group, Host, and Address. Only a subset of keywords may be used on the lines following a Match keyword. Available keywords are AllowTcpForwarding, - ForceCommand, GatewayPorts, PermitOpen, X11DisplayOffset, - X11Forwarding, and X11UseLocalHost. + ForceCommand, GatewayPorts, PermitOpen, HostbasedAlgorithms, + PubkeyAlgorithms, X11DisplayOffset, X11Forwarding, and + X11UseLocalHost. MaxAuthTries Specifies the maximum number of authentication attempts permitted @@ -304,20 +384,20 @@ MaxStartups Specifies the maximum number of concurrent unauthenticated con- nections to the SSH 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. "10:30:60"). sshd(8) will refuse connection attempts with a probability of ``rate/100'' (30%) if there are currently - ``start'' (10) unauthenticated connections. The probability in- - creases linearly and all connection attempts are refused if the + ``start'' (10) unauthenticated connections. The probability + increases linearly and all connection attempts are refused if the number of 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 @@ -333,10 +413,10 @@ PermitOpen IPv4_addr:port PermitOpen [IPv6_addr]:port - Multiple forwards may be specified by separating them with - whitespace. An argument of ``any'' can be used to remove all re- - strictions and permit any forwarding requests. By default all - port forwarding requests are permitted. + Multiple forwards may be specified by separating them with white- + space. An argument of ``any'' can be used to remove all restric- + tions and permit any forwarding requests. By default all port + forwarding requests are permitted. PermitRootLogin Specifies whether root can log in using ssh(1). The argument @@ -357,15 +437,15 @@ PermitTunnel Specifies whether tun(4) device forwarding is allowed. The argu- ment must be ``yes'', ``point-to-point'' (layer 3), ``ethernet'' - (layer 2), or ``no''. Specifying ``yes'' permits both ``point- - to-point'' and ``ethernet''. The default is ``no''. + (layer 2), or ``no''. Specifying ``yes'' permits both + ``point-to-point'' and ``ethernet''. The default is ``no''. PermitUserEnvironment Specifies whether ~/.ssh/environment and environment= options in ~/.ssh/authorized_keys are processed by sshd(8). 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 SSH dae- @@ -387,27 +467,35 @@ Protocol Specifies the protocol versions sshd(8) supports. The possible - values are `1' and `2'. Multiple versions must be comma-separat- - ed. The default is ``2,1''. Note that the order of the protocol - list does not indicate preference, because the client selects - among multiple protocol versions offered by the server. Specify- - ing ``2,1'' is identical to ``1,2''. + values 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 + 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 @@ -425,24 +513,24 @@ Arguments should be a subsystem name and a command (with optional arguments) 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 ap- - plies to protocol version 2 only. + 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(8). The possible values are: DAEMON, USER, AUTH, LOCAL0, - LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The de- - fault is AUTH. + LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The + default is AUTH. TCPKeepAlive Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, - 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. + this means that connections will die if the route is down tempo- + rarily, 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 + resources. The default is ``yes'' (to send TCP keepalive messages), and the server will notice if the network goes down or the client host @@ -458,16 +546,16 @@ 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. UsePAM Enables the Pluggable Authentication Module interface. If set to ``yes'' this will enable PAM authentication using - ChallengeResponseAuthentication and PasswordAuthentication in ad- - dition to PAM account and session module processing for all au- - thentication types. + ChallengeResponseAuthentication and PasswordAuthentication in + addition to PAM account and session module processing for all + authentication types. Because PAM challenge-response authentication usually serves an equivalent role to password authentication, you should disable @@ -477,14 +565,36 @@ non-root user. The default is ``no''. UsePrivilegeSeparation - Specifies whether sshd(8) separates privileges by creating an un- - privileged child process to deal with incoming network traffic. + Specifies whether sshd(8) 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: + 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. + 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(8)'s X11 forwarding. This prevents sshd from interfering with real X11 @@ -499,13 +609,14 @@ is configured to listen on the wildcard address (see X11UseLocalhost below), though this is not the default. Addi- tionally, the authentication spoofing and authentication data - verification and substitution occur on the client side. The se- - curity risk of using X11 forwarding is that the client's X11 dis- - play server may be exposed to attack when the SSH client requests - forwarding (see the warnings for ForwardX11 in ssh_config(5)). A - system administrator may have a stance in which they want to pro- - tect clients that may expose themselves to attack by unwittingly - requesting X11 forwarding, which can warrant a ``no'' setting. + 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 administrator may have a stance in + which they want to protect clients that may expose themselves to + attack by unwittingly requesting X11 forwarding, which can war- + rant a ``no'' setting. Note that disabling X11 forwarding does not prevent users from forwarding X11 traffic, as users can always install their own @@ -521,16 +632,34 @@ 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 is /usr/X11R6/bin/xauth. TIME FORMATS - sshd(8) command-line arguments and configuration file options that speci- - fy time may be expressed using a sequence of the form: time[qualifier], + sshd(8) command-line arguments and configuration file options that spec- + ify time may be expressed using a sequence of the form: time[qualifier], where time is a positive integer value and qualifier is one of the fol- lowing: @@ -550,6 +679,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(8). This file should be @@ -565,6 +707,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 4.0 September 25, 1999 9 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/sshd_config.5 openssh-4.5p1+x509-6.1/sshd_config.5 --- openssh-4.5p1/sshd_config.5 2006-08-30 04:06:34.000000000 +0300 +++ openssh-4.5p1+x509-6.1/sshd_config.5 2007-10-25 19: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.70 2006/08/21 08:14:01 dtucker Exp $ +.\" $OpenBSD$ .Dd September 25, 1999 .Dt SSHD_CONFIG 5 .Os @@ -97,6 +98,20 @@ (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 -tag -width Ds -compact +.It Cm sslclient | Cm SSL client | Cm SSL_client | Cm client +only SSL-client purpose +.It Cm any | Cm Any Purpose | Cm Any_Purpose | Cm AnyPurpose +allow any purpose +.It Cm skip | Cm '' Li (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. @@ -167,6 +182,60 @@ 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 = +! +LDAP initialization method may require URL to be escaped, i.e. use +.Sq %2C +instead of +.Sq \&, +(comma). +Escaped URL don't depend from LDAP initialization method. +.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 @@ -326,6 +395,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 @@ -372,6 +451,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 @@ -424,6 +505,28 @@ file on logout. The 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). @@ -492,6 +595,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 Match Introduces a conditional block. If all of the criteria on the @@ -517,6 +629,8 @@ .Cm ForceCommand , .Cm GatewayPorts , .Cm PermitOpen , +.Cm HostbasedAlgorithms , +.Cm PubkeyAlgorithms , .Cm X11DisplayOffset , .Cm X11Forwarding , and @@ -698,6 +812,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 @@ -826,6 +950,51 @@ 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 -tag -offset indent -compact +.It none +do not use OCSP to validate certificates; +.It ocspcert +validate only certificates that specify +.Sq "OCSP Service Locator" +URL; +.It 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 .Xr sshd 8 Ns 's @@ -891,6 +1060,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 @@ -939,6 +1150,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 @@ -960,3 +1208,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.5p1/ssh-keygen.0 openssh-4.5p1+x509-6.1/ssh-keygen.0 --- openssh-4.5p1/ssh-keygen.0 2006-11-07 15:07:21.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keygen.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-KEYGEN(1) OpenBSD Reference Manual SSH-KEYGEN(1) +SSH-KEYGEN(1) BSD General Commands Manual SSH-KEYGEN(1) NAME - ssh-keygen - authentication key generation, management and conversion + ssh-keygen -- authentication key generation, management and conversion SYNOPSIS ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment] @@ -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 @@ -44,14 +44,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 @@ -78,8 +78,8 @@ -b bits Specifies the number of bits in the key to create. For RSA keys, the minimum size is 768 bits and the default is 2048 bits. Gen- - erally, 2048 bits is considered sufficient. DSA keys must be ex- - actly 1024 bits as specified by FIPS 186-2. + erally, 2048 bits is considered sufficient. DSA keys must be + exactly 1024 bits as specified by FIPS 186-2. -C comment Provides a new comment. @@ -93,7 +93,7 @@ Download the RSA public key stored in the smartcard in reader. -e This option will read a private or public OpenSSH key file and - print the key in a `SECSH Public Key File Format' to stdout. + print the key in a 'SECSH Public Key File Format' to stdout. This option allows exporting keys for use by several commercial SSH implementations. @@ -113,8 +113,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 @@ -124,13 +124,15 @@ -i This option will read an unencrypted private (or public) key file in SSH2-compatible format and print an OpenSSH compatible private - (or public) key to stdout. ssh-keygen also reads the `SECSH + (or public) key to stdout. ssh-keygen also reads the 'SECSH Public Key File Format'. This option allows importing keys from several commercial SSH implementations. -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- @@ -156,7 +158,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 @@ -188,10 +191,10 @@ 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). + Exchange (DH-GEX) protocol. Generating these groups is a two-step + process: 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: @@ -222,8 +225,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 @@ -238,35 +241,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 @@ -281,8 +300,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 4.0 September 25, 1999 5 +BSD September 25, 1999 BSD diff -ruN openssh-4.5p1/ssh-keygen.1 openssh-4.5p1+x509-6.1/ssh-keygen.1 --- openssh-4.5p1/ssh-keygen.1 2005-11-28 07:41:47.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keygen.1 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.72 2005/11/28 05:16:53 dtucker 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 @@ -262,6 +263,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. @@ -294,6 +296,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 @@ -404,6 +407,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 @@ -420,8 +425,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 @@ -438,6 +462,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 @@ -466,3 +507,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.5p1/ssh-keygen.c openssh-4.5p1+x509-6.1/ssh-keygen.c --- openssh-4.5p1/ssh-keygen.c 2006-11-07 14:14:42.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keygen.c 2006-11-08 09:06:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.155 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD$ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -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) 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" @@ -47,6 +70,7 @@ #include "match.h" #include "hostfile.h" #include "dns.h" +#include "ssh-xkalg.h" #ifdef SMARTCARD #include "scard.h" @@ -1074,6 +1098,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.5p1/ssh-keyscan.0 openssh-4.5p1+x509-6.1/ssh-keyscan.0 --- openssh-4.5p1/ssh-keyscan.0 2006-11-07 15:07:21.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keyscan.0 2007-08-29 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-KEYSCAN(1) OpenBSD Reference Manual SSH-KEYSCAN(1) +SSH-KEYSCAN(1) BSD General Commands Manual SSH-KEYSCAN(1) NAME - ssh-keyscan - gather ssh public keys + ssh-keyscan -- gather ssh public keys SYNOPSIS ssh-keyscan [-46Hv] [-f file] [-p port] [-T timeout] [-t type] @@ -17,8 +17,8 @@ sible in parallel, so it is very efficient. The keys from a domain of 1,000 hosts can be collected in tens of seconds, even when some of those hosts are down or do not run ssh. For scanning, one does not need login - access to the machines that are being scanned, nor does the scanning pro- - cess involve any encryption. + access to the machines that are being scanned, nor does the scanning + process involve any encryption. The options are as follows: @@ -42,15 +42,16 @@ 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 - be specified by separating them with commas. The default is - ``rsa1''. + ``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 are + keys for protocol version 2. -v Verbose mode. Causes ssh-keyscan to print debugging messages about its progress. @@ -59,8 +60,8 @@ If an 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. + 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 4.0 January 1, 1996 2 +BSD January 1, 1996 BSD diff -ruN openssh-4.5p1/ssh-keyscan.1 openssh-4.5p1+x509-6.1/ssh-keyscan.1 --- openssh-4.5p1/ssh-keyscan.1 2006-10-18 00:53:07.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-keyscan.1 2007-08-29 09:06:00.000000000 +0300 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.22 2006/09/25 04:55:38 ray 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,13 +111,16 @@ 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 -.Dq rsa1 . +The default are keys for protocol version 2. .It Fl v Verbose mode. Causes @@ -134,6 +160,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 +187,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 @@ -161,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.5p1/ssh-keyscan.c openssh-4.5p1+x509-6.1/ssh-keyscan.c --- openssh-4.5p1/ssh-keyscan.c 2006-10-23 20:01:16.000000000 +0300 +++ openssh-4.5p1+x509-6.1/ssh-keyscan.c 2007-08-29 09:06:01.000000000 +0300 @@ -1,10 +1,33 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.74 2006/10/06 02:29:19 djm Exp $ */ +/* $OpenBSD$ */ /* * Copyright 1995, 1996 by David Mazieres . * * 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" @@ -35,6 +58,8 @@ #include "ssh1.h" #include "buffer.h" #include "key.h" +#include "ssh-x509.h" +#include "ssh-xkalg.h" #include "cipher.h" #include "kex.h" #include "compat.h" @@ -52,11 +77,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 = NULL; int hash_hosts = 0; /* Hash hostname on output */ @@ -90,7 +111,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 */ @@ -286,7 +307,7 @@ * null token for two adjacent separators, so we may have to loop. */ static char * -strnnsep(char **stringp, char *delim) +strnnsep(char **stringp, const char *delim) { char *tok; @@ -360,8 +381,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; @@ -394,7 +414,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); } @@ -432,7 +461,7 @@ } static int -conalloc(char *iname, char *oname, int keytype) +conalloc(char *iname, char *oname, const char *keyname) { char *namebase, *name, *namelist; int s; @@ -461,7 +490,11 @@ fdcon[s].c_data = (char *) &fdcon[s].c_plen; fdcon[s].c_len = 4; fdcon[s].c_off = 0; - fdcon[s].c_keytype = keytype; +{ + Key *k = key_new(key_type_from_name((char*)keyname)); + fdcon[s].c_keyname = key_ssh_name(k); + key_free(k); +} gettimeofday(&fdcon[s].c_tv, NULL); fdcon[s].c_tv.tv_sec += timeout; TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); @@ -481,7 +514,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--; @@ -502,7 +535,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); } @@ -515,6 +548,7 @@ char remote_version[sizeof buf]; size_t bufsiz; con *c = &fdcon[s]; + int rsa1key; for (;;) { memset(buf, '\0', sizeof(buf)); @@ -554,7 +588,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); @@ -567,8 +602,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); @@ -579,7 +614,7 @@ confree(s); return; } - if (c->c_keytype != KT_RSA1) { + if (!rsa1key) { keyprint(c, keygrab_ssh2(c)); confree(s); return; @@ -683,16 +718,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); } } @@ -740,6 +777,8 @@ if (argc <= 1) usage(); + fill_default_xkalg(); + get_keynames = xstrdup("x509v3-sign-dss,x509v3-sign-rsa,ssh-rsa,ssh-dss"); /* Get all protocol v2 keys by default */ while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) { switch (opt) { case 'H': @@ -775,23 +814,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.5p1/ssh-keysign.0 openssh-4.5p1+x509-6.1/ssh-keysign.0 --- openssh-4.5p1/ssh-keysign.0 2006-11-07 15:07:27.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keysign.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-KEYSIGN(8) OpenBSD System Manager's Manual SSH-KEYSIGN(8) +SSH-KEYSIGN(8) BSD System Manager's Manual SSH-KEYSIGN(8) NAME - ssh-keysign - ssh helper program for host-based authentication + ssh-keysign -- ssh helper program for host-based authentication SYNOPSIS ssh-keysign @@ -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 - host-based authentication is used. + host-based 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 4.0 May 24, 2002 1 +BSD May 24, 2002 BSD diff -ruN openssh-4.5p1/ssh-keysign.8 openssh-4.5p1+x509-6.1/ssh-keysign.8 --- openssh-4.5p1/ssh-keysign.8 2006-03-15 02:55:32.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-keysign.8 2006-11-08 09:06:00.000000000 +0200 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.8 2006/02/24 20:22:16 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 host-based 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.5p1/ssh-ocsp.c openssh-4.5p1+x509-6.1/ssh-ocsp.c --- openssh-4.5p1/ssh-ocsp.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-ocsp.c 2007-10-04 23:12:47.000000000 +0300 @@ -0,0 +1,1012 @@ +/* + * Copyright (c) 2004-2007 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 + +#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 = ssh_X509_NAME_oneline(X509_get_subject_name(cert)); /*fatal on error*/ + 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; + + /* we don't need to clean items */ + if (conn->path != NULL) xfree((void*)conn->path); + 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) { + if (q[1] != '\x0') conn->path = xstrdup(q); /*fatal on error*/ + *q = '\x0'; + /* now p(conn->host) point only to host{:port} */ + } + /*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 + } + +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 accept 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 *x = sk_X509_value(vacrts, k); + buf = ssh_X509_NAME_oneline(X509_get_subject_name(x)); /*fatal on error*/ + logit("ssh_ocsp_get_basicresp: VA[%d] subject='%s'", k, buf); + xfree(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, 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 = ssh_X509_NAME_oneline(X509_get_subject_name(cert)); /*fatal on error*/ + debug3("ssh_ocsp_validate: for '%s'", buf); + xfree(buf); + } + + switch (va.type) { + default: + /*when something is missing*/ + fatal("ssh_ocsp_validate: invalid validator type %d", va.type); + break; /*;-)*/ + case SSHVA_NONE: + debug3("ssh_ocsp_validate: 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.5p1/ssh-rand-helper.0 openssh-4.5p1+x509-6.1/ssh-rand-helper.0 --- openssh-4.5p1/ssh-rand-helper.0 2006-11-07 15:07:26.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-rand-helper.0 2007-08-07 09:06:00.000000000 +0300 @@ -1,7 +1,7 @@ -SSH-RAND-HELPER(8) OpenBSD System Manager's Manual SSH-RAND-HELPER(8) +SSH-RAND-HELPER(8) BSD System Manager's Manual SSH-RAND-HELPER(8) NAME - ssh-rand-helper - Random number gatherer for OpenSSH + ssh-rand-helper -- Random number gatherer for OpenSSH SYNOPSIS ssh-rand-hlper [-vxXh] [-b bytes] @@ -46,4 +46,4 @@ SEE ALSO ssh(1), ssh-add(1), ssh-keygen(1), sshd(8) -OpenBSD 4.0 April 14, 2002 1 +BSD April 14, 2002 BSD diff -ruN openssh-4.5p1/ssh-x509.c openssh-4.5p1+x509-6.1/ssh-x509.c --- openssh-4.5p1/ssh-x509.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-x509.c 2007-10-24 01:09:03.000000000 +0300 @@ -0,0 +1,1144 @@ +/* + * Copyright (c) 2002-2007 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 +#include + +#include "ssh-xkalg.h" +#include "log.h" +#include +#include "xmalloc.h" +#include "uuencode.h" +#include +#include "x509store.h" +#include "compat.h" + +#ifndef ISSPACE +# define ISSPACE(ch) (isspace((int)(unsigned char)(ch))) +#endif + +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); +} + + +int +ssh_X509_NAME_print(BIO* bio, X509_NAME *xn) { + static u_long print_flags = ((XN_FLAG_ONELINE & \ + ~XN_FLAG_SPC_EQ & \ + ~XN_FLAG_SEP_MASK) | \ + XN_FLAG_SEP_COMMA_PLUS); + + if (xn == NULL) return(-1); + + X509_NAME_print_ex(bio, xn, 0, print_flags); + BIO_flush(bio); + + return(BIO_pending(bio)); +} + + +char* +ssh_X509_NAME_oneline(X509_NAME *xn) { + char *buf = NULL; + int size; + BIO* mbio = NULL; + + if (xn == NULL) return(NULL); + + mbio = BIO_new(BIO_s_mem()); + if (mbio == NULL) return(buf); + + size = ssh_X509_NAME_print(mbio, xn); + if (size <= 0) { + error("ssh_X509_NAME_oneline: no data in buffer"); + goto done; + } + + buf = xmalloc(size + 1); /*fatal on error*/ + + /* we should request one byte more !?!? */ + if (size != BIO_gets(mbio, buf, size + 1)) { + error("ssh_X509_NAME_oneline: cannot get data from buffer"); + goto done; + } + buf[size] = '\0'; + +done: + /* This call will walk the chain freeing all the BIOs */ + BIO_free_all(mbio); + + 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(*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(*p); p++) + {/*skip space*/} + if (!*p) { + error("x509key_find_subject: no data after keyword"); + return(NULL); + } + if (*p == ':' || *p == '=') { + for (p++; *p && ISSPACE(*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(*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 unsigned long +ssh_hctol(u_char ch) { +/* '0'-'9' = 0x30 - 0x39 (ascii) */ +/* 'A'-'F' = 0x41 - 0x46 (ascii) */ +/* 'a'-'f' = 0x61 - 0x66 (ascii) */ +/* should work for EBCDIC */ + if (('0' <= ch) && (ch <= '9')) { + return((long)(ch - '0')); + } + if (('A' <= ch) && (ch <= 'F')) { + return((long)(ch - ('A' - 10))); + } + if (('a' <= ch) && (ch <= 'f')) { + return((long)(ch - ('a' - 10))); + } + + return(-1); +} + + +static unsigned long +ssh_hatol(const u_char *str, size_t maxsize) { + int k; + long v, ret = 0; + + for(k = maxsize; k > 0; k--, str++) { + v = ssh_hctol(*str); + if (v < 0) return(-1); + ret = (ret << 4) + v; + } + return(ret); +} + + +static int +get_escsymbol(const u_char* str, size_t len, u_long *value) { + const char ch = *str; + long v; + + if (len < 1) { + error("get_escsymbol:" + " missing characters in escape sequence"); + return(-1); + } + + /*escape formats: + "{\\}\\W%08lX" + "{\\}\\U%04lX" + "{\\}\\%02X" + "{\\}\\x%02X" - X509_NAME_oneline format + */ + if (ch == '\\') { + if (value) *value = ch; + return(1); + } + if (ch == 'W') { + if (len < 9) { + error("get_escsymbol:" + " to short 32-bit escape sequence"); + return(-1); + } + v = ssh_hatol(++str, 8); + if (v < 0) { + error("get_escsymbol:" + " invalid character in 32-bit hex sequence"); + return(-1); + } + if (value) *value = v; + return(9); + } + if (ch == 'U') { + if (len < 5) { + error("get_escsymbol:" + " to short 16-bit escape sequence"); + return(-1); + } + v = ssh_hatol(++str, 4); + if (v < 0) { + error("get_escsymbol:" + " invalid character in 16-bit hex sequence"); + return(-1); + } + if (value) *value = v; + return(5); + } +#if 0 +/* +The code bellow isn't correct. Let 'O' is not 8-bit string(as example +BMPString) then "X509_NAME_oneline" will output "\x00O"(!). +The X509_NAME_oneline output format will left unsupported, i.e.: +Unsupported: +$ openssl x509 -in cert_file -subject -noout +Supported: + v0.9.7+ +$ openssl x509 -in cert_file -subject -noout -nameopt oneline[,] + v0.9.6 +$ openssl x509 -in cert_file -subject -noout -nameopt oneline [-nameopt ] +*/ + if ((ch == 'x') || (ch == 'X')) { + if (len < 3) { + error("get_escsymbol:" + " to short 8-bit hex sequence"); + return(-1); + } + v = ssh_hatol(++str, 2); + if (v < 0) { + error("get_escsymbol:" + " invalid character in 8-bit hex sequence"); + return(-1); + } + if (value) *value = v; + return(3); + } +#endif + v = ssh_hctol(*str); + if (v < 0) { + /*a character is escaped ?*/ + if (*str > 127) { /*ASCII comparision !*/ + /* there is no reason symbol above 127 + to be escaped in this way */ + error("get_escsymbol:" + " non-ascii character in escape sequence"); + return(-1); + } + if (value) *value = *str; + return(1); + } + + /*two hex numbers*/ + { + long vlo; + if (len < 2) { + error("get_escsymbol:" + " to short 8-bit escape sequence"); + return(-1); + } + vlo = ssh_hctol(*++str); + if (vlo < 0) { + error("get_escsymbol:" + " invalid character in 8-bit hex sequence"); + return(-1); + } + v = (v << 4) + vlo; + } + if (value) *value = v; + return(2); +} +#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 u_char* str, size_t len) { +/* default maxsizes: + C: 2 + L, ST: 128 + O, OU, CN: 64 + emailAddress: 128 +*/ + u_char buf[129*6+1]; /*enough for 128 UTF-8 symbols*/ + int ret = 0; + int type = MBSTRING_ASC; + u_long ch; + u_char *p; + const u_char *q; + size_t k; + + /*this is internal method and we don't check validity of some arguments*/ + + p = buf; + q = str; + k = sizeof(buf); + + while ((len > 0) && (k > 0)) { + int ch_utf8 = 1; + if (*q == '\0') { + error("ssh_X509_NAME_add_entry_by_NID:" + " unsupported zero(NIL) symbol in name"); + return(0); + } + if (*q == '\\') { + len--; + if (len <= 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " escape sequence without data"); + return(0); + } + + ret = get_escsymbol(++q, len, &ch); + if (ret < 0) return(0); + if (ret == 2) { + /*escaped two hex numbers*/ + ch_utf8 = 0; + } + } else { + ret = UTF8_getc(q, len, &ch); + if(ret < 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " cannot get next symbol(%.32s)" + , q); + return(0); + } + } + len -= ret; + q += ret; + + if (ch_utf8) { + /* UTF8_putc return negative if buffer is too short */ + ret = UTF8_putc(p, k, ch); + if (ret < 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " UTF8_putc fail for symbol %ld", ch); + return(0); + } + } else { + *p = (u_char)ch; + ret = 1; + } + k -= ret; + p += ret; + } + if (len > 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " too long data"); + return(0); + } + *p = '\0'; + + for (p = buf; *p; p++) { + if (*p > 127) { + type = MBSTRING_UTF8; + break; + } + } + k = strlen((char*)buf); + + debug3("ssh_X509_NAME_add_entry_by_NID:" + " type=%s, k=%d" + , ((type == MBSTRING_ASC) ? "ASCII" : "UTF-8") + , k + ); + + /* this method will fail if string exceed max size limit for nid */ + ret = X509_NAME_add_entry_by_NID(name, nid, type, buf, (int)k, -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='%.512s'" + , 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(*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; + } + { + char *s = q; + for(--s; ISSPACE(*s) && (s > p); s--) + {/*skip trailing space*/} + *++s = 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 (; *p && ISSPACE(*p); p++) + {/*skip space*/} + for (q = token - 1; (q >= p) && ISSPACE(*q); q--) + {/*skip unexpected \n, etc. from end*/} + *++q = 0; + + ret = ssh_X509_NAME_add_entry_by_NID(_name, nid, (u_char*)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, [%.1024s]) called", + _keytype, (_cp ? _cp : "")); + subject = x509key_find_subject(_cp); + if (subject == NULL) + return(NULL); + + debug3("x509key_from_subject: subject=[%.1024s]", 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) { + X509_NAME *dn; + + if (!x509key_check("x509key_subject", key)) return(NULL); + + /* it is better to match format used in x509key_write_subject */ + dn = X509_get_subject_name(key->x509); + return(ssh_X509_NAME_oneline(dn)); /*fatal on error*/ +} + + +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; + + 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:"); + ssh_X509_NAME_print(out, X509_get_subject_name(key->x509)); + + 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; + + 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= "); + ssh_X509_NAME_print(out, X509_get_issuer_name(x509)); + BIO_puts(out, "\n"); + + BIO_puts(out, "subject= "); + ssh_X509_NAME_print(out, X509_get_subject_name(x509)); + 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 = NULL; + int keylen = 0; + u_char *sigret = NULL; + 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) { + keylen = EVP_PKEY_size(privkey); + if (keylen > 0) { + sigret = xmalloc(keylen); /*fatal on error*/ + } else { + error("ssh_x509_sign: cannot get key size for 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); + debug3("ssh_x509_sign: keylen=%d, siglen=%u", keylen, siglen); + 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); + } + if (sigret) { + memset(sigret, 's', keylen); + xfree(sigret); + } + 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.5p1/ssh-x509.h openssh-4.5p1+x509-6.1/ssh-x509.h --- openssh-4.5p1/ssh-x509.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-x509.h 2007-10-04 22:56:18.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.5p1/ssh-xkalg.c openssh-4.5p1+x509-6.1/ssh-xkalg.c --- openssh-4.5p1/ssh-xkalg.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-xkalg.c 2007-08-06 21:20:15.000000000 +0300 @@ -0,0 +1,482 @@ +/* + * 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 + +#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); +} + + +#ifdef HAVE_EVP_MD_CTX_MD_DATA +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)); +} +#endif /*def HAVE_EVP_MD_CTX_MD_DATA*/ + + +#ifdef HAVE_EVP_MD_FLAGS +#ifndef EVP_MD_FLAG_FIPS +# define EVP_MD_FLAG_FIPS 0 +#endif +#endif /*def HAVE_EVP_MD_FLAGS*/ + +static const +EVP_MD dss1_md = { + NID_dsa, + NID_dsaWithSHA1, + SHA_DIGEST_LENGTH, +#ifdef HAVE_EVP_MD_FLAGS + EVP_MD_FLAG_FIPS, +#endif /*def HAVE_EVP_MD_FLAGS*/ +#ifdef HAVE_EVP_MD_CTX_MD_DATA + init, + update, + final, +#else + SHA1_Init, + SHA1_Update, + SHA1_Final, +#endif /*ndef HAVE_EVP_MD_CTX_MD_DATA*/ +#ifdef HAVE_EVP_MD_COPY + NULL, +#endif /*def HAVE_EVP_MD_COPY*/ +#ifdef HAVE_EVP_MD_CLEANUP + NULL, +#endif /*def HAVE_EVP_MD_CLEANUP*/ + 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.5p1/ssh-xkalg.h openssh-4.5p1+x509-6.1/ssh-xkalg.h --- openssh-4.5p1/ssh-xkalg.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/ssh-xkalg.h 2005-08-13 14:59:26.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.5p1/tests/CA/1-cre_cadb.sh openssh-4.5p1+x509-6.1/tests/CA/1-cre_cadb.sh --- openssh-4.5p1/tests/CA/1-cre_cadb.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/1-cre_cadb.sh 2007-02-27 23:22:48.000000000 +0200 @@ -0,0 +1,339 @@ +#! /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.5p1/tests/CA/2-cre_cakeys.sh openssh-4.5p1+x509-6.1/tests/CA/2-cre_cakeys.sh --- openssh-4.5p1/tests/CA/2-cre_cakeys.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/2-cre_cakeys.sh 2006-03-12 23:01:31.000000000 +0200 @@ -0,0 +1,253 @@ +#! /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 "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}" \ + $SSH_DN_UTF8_FLAG \ + -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}" \ + $SSH_DN_UTF8_FLAG \ + -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.5p1/tests/CA/3-cre_certs.sh openssh-4.5p1+x509-6.1/tests/CA/3-cre_certs.sh --- openssh-4.5p1/tests/CA/3-cre_certs.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/3-cre_certs.sh 2007-02-17 20:35:58.000000000 +0200 @@ -0,0 +1,274 @@ +#! /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 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.5p1/tests/CA/4-cre_crls.sh openssh-4.5p1+x509-6.1/tests/CA/4-cre_crls.sh --- openssh-4.5p1/tests/CA/4-cre_crls.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/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.5p1/tests/CA/5-cre_ldap.sh openssh-4.5p1+x509-6.1/tests/CA/5-cre_ldap.sh --- openssh-4.5p1/tests/CA/5-cre_ldap.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/5-cre_ldap.sh 2007-08-28 01:08:11.000000000 +0300 @@ -0,0 +1,127 @@ +#! /bin/sh +# Copyright (c) 2004-2007 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.5p1/tests/CA/config openssh-4.5p1+x509-6.1/tests/CA/config --- openssh-4.5p1/tests/CA/config 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/config 2007-10-22 22:30:27.000000000 +0300 @@ -0,0 +1,192 @@ +# 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" + +SSH_DN_UTF8_FLAG='-utf8' +# '-utf8' flag is added in OpenSSL 0.9.7 +case "`${OPENSSL} version`" in + *0.9.6*) + SSH_DN_UTF8_FLAG= + ;; + *);; +esac +if test -n "${SSH_DN_UTF8_FLAG}"; then + SSH_DN_L="$SSH_DN_L cyrillic-АБВГабвг greek-ΑΒΓΔαβγδ" + SSH_DN_O="$SSH_DN_O cyrillic-АБВГабвг greek-ΑΒΓΔαβγδ" + SSH_DN_OU="$SSH_DN_OU cyrillic-АБВГабвг greek-ΑΒΓΔαβγδ" +fi + +# 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.5p1/tests/CA/env.in openssh-4.5p1+x509-6.1/tests/CA/env.in --- openssh-4.5p1/tests/CA/env.in 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/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.5p1/tests/CA/functions openssh-4.5p1+x509-6.1/tests/CA/functions --- openssh-4.5p1/tests/CA/functions 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/functions 2007-02-11 18:29:44.000000000 +0200 @@ -0,0 +1,287 @@ +# 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=$? +# + if test -n "${SSH_DN_UTF8_FLAG}"; then + NAMEOPT="-nameopt utf8,sep_comma_plus" #ok + #NAMEOPT="-nameopt esc_2253,esc_ctrl,esc_msb,utf8,dump_nostr,dump_der,use_quote,sep_comma_plus_space,sname" #fail - esc_msb should be removed + #NAMEOPT="-nameopt esc_2253,esc_ctrl,utf8,dump_nostr,dump_der,use_quote,sep_comma_plus_space,sname" #ok + #NAMEOPT="-nameopt esc_2253,esc_ctrl,-esc_msb,utf8,dump_nostr,dump_der,use_quote,sep_comma_plus_space,sname" #ok + #NAMEOPT="-nameopt esc_2253,esc_ctrl,esc_msb,utf8,dump_nostr,dump_der,use_quote,sep_comma_plus_space,sname,-esc_msb" #ok + #NAMEOPT="-nameopt oneline,-esc_msb,-space_eq" #ok + #NAMEOPT="-nameopt oneline,-esc_msb" #now ok (spaces around '=') + else + NAMEOPT= + fi + subject=`"${OPENSSL}" x509 -noout -subject ${NAMEOPT} -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}" +} + + +# === +utf8base64() { + if test -n "${SSH_DN_UTF8_FLAG}"; then + printf ':' + printf "$1" | ${OPENSSL} enc -a -e | xargs printf ' %s\n' + else + printf " $1" + fi +} + + +# === +FUNCTIONS_INCLUDED="yes" diff -ruN openssh-4.5p1/tests/CA/Makefile.in openssh-4.5p1+x509-6.1/tests/CA/Makefile.in --- openssh-4.5p1/tests/CA/Makefile.in 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/Makefile.in 2007-01-27 16:59:16.000000000 +0200 @@ -0,0 +1,134 @@ +srcdir=@srcdir@ +@OCSP_ON@SSH_OCSP=yes +@OCSP_OFF@SSH_OCSP=no +RSAKEYBITS=2048 + + +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 $(RSAKEYBITS) -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 -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 $(RSAKEYBITS) -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 -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 $(RSAKEYBITS) -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 -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.5p1/tests/CA/openssh_tests.sh openssh-4.5p1+x509-6.1/tests/CA/openssh_tests.sh --- openssh-4.5p1/tests/CA/openssh_tests.sh 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/openssh_tests.sh 2007-01-29 01:17:54.000000000 +0200 @@ -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.5p1/tests/CA/shell.rc openssh-4.5p1+x509-6.1/tests/CA/shell.rc --- openssh-4.5p1/tests/CA/shell.rc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/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.5p1/tests/CA/test-agent.sh.inc openssh-4.5p1+x509-6.1/tests/CA/test-agent.sh.inc --- openssh-4.5p1/tests/CA/test-agent.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/test-agent.sh.inc 2007-02-27 22:56:10.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 from 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.5p1/tests/CA/test-blob_auth.sh.inc openssh-4.5p1+x509-6.1/tests/CA/test-blob_auth.sh.inc --- openssh-4.5p1/tests/CA/test-blob_auth.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/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' -e 's|,|%2C|'` + 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 -nameopt -esc_msb` || 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.5p1/tests/CA/test-ocsp.sh.inc openssh-4.5p1+x509-6.1/tests/CA/test-ocsp.sh.inc --- openssh-4.5p1/tests/CA/test-ocsp.sh.inc 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/tests/CA/test-ocsp.sh.inc 2006-09-01 00:35:03.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" < +#ifndef LDAP_DEPRECATED + /* to suppress warnings in some 2.3x versions */ +# define LDAP_DEPRECATED 0 +#endif +#include + + +/* ================================================================== */ +/* 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)); +} + + +/* ================================================================== */ +/* wrappers to some depricated functions */ +static void +ldaplookup_parse_result ( + LDAP *ld, + LDAPMessage *res +) { + static const int freeit = 0; + int result; +#ifdef HAVE_LDAP_PARSE_RESULT + int ret; + char *matcheddn; + char *errmsg; + + ret = ldap_parse_result(ld, res, &result, &matcheddn, &errmsg, NULL, NULL, freeit); + if (ret == LDAP_SUCCESS) { + if (errmsg) ERR_add_error_data(1, errmsg); + } + if (matcheddn) ldap_memfree(matcheddn); + if (errmsg) ldap_memfree(errmsg); +#else + result = ldap_result2error(ld, res, freeit); + openssl_add_ldap_error(result); +#endif +} + + +static int +ldaplookup_bind_s(LDAP *ld) { + int result; + + /* anonymous bind - data must be retrieved by anybody */ +#ifdef HAVE_LDAP_SASL_BIND_S +{ + static struct berval cred = { 0, (char*)"" }; + + result = ldap_sasl_bind_s( + ld, NULL/*dn*/, LDAP_SASL_SIMPLE, &cred, + NULL, NULL, NULL); +} +#else + result = ldap_simple_bind_s(ld, NULL/*binddn*/, NULL/*bindpw*/); +#endif + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_bind_s:" +" ldap_XXX_bind_s return 0x%x(%s)\n" +, result, ldap_err2string(result)); +#endif + return(result); +} + + +static int +ldaplookup_search_s( + LDAP *ld, + LDAP_CONST char *base, + int scope, + LDAP_CONST char *filter, + char **attrs, + int attrsonly, + LDAPMessage **res +) { + int result; +#ifdef HAVE_LDAP_SEARCH_EXT_S + result = ldap_search_ext_s(ld, base, + scope, filter, attrs, attrsonly, + NULL, NULL, NULL, 0, res); +#else + result = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res); +#endif + +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_search_s:" +"\n base=%s\n filter=%s\n" +" ldap_search_{XXX}s return 0x%x(%s)\n" +, base, filter +, result, ldap_err2string(result)); +#endif + return(result); +} + + +/* ================================================================== */ +/* 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; + + (void)argl; + (void)retp; +#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 + (void)ctx; + return(1); +} + + +static int +ldaplookup_shutdown(X509_LOOKUP *ctx) { +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_shutdown:\n"); +#endif + (void)ctx; + 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(p->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 */ +#ifdef HAVE_LDAP_INITIALIZE + ret = ldap_initialize(&p->ld, p->url); + if (ret != LDAP_SUCCESS) { + X509byLDAPerr(X509byLDAP_F_LDAPHOST_NEW, X509byLDAP_R_INITIALIZATION_ERROR); + openssl_add_ldap_error(ret); + goto error; + } +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaphost_new: ldap_initialize(..., url=%s)\n", p->url); +#endif +#else /*ndef HAVE_LDAP_INITIALIZE*/ + 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; + } +#endif /*ndef HAVE_LDAP_INITIALIZE*/ + + { + 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; +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_set_protocol(..., %s) p=%p\n", ver, (void*)p); +#endif + 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_attr(ASN1_STRING *nv) { + char *p = NULL; + int k; + BIO *mbio; + + mbio = BIO_new(BIO_s_mem()); + if (mbio == NULL) return(NULL); + + k = ASN1_STRING_print_ex(mbio, nv, XN_FLAG_RFC2253); + 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 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; +#if 0 + /* + 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); + } + } +#else + { + char *q, *s; + + q = ldaplookup_attr(nv); + if (q == NULL) goto done; +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_filter: ldaplookup_attr(nv) return '%.512s'\n", q); +#endif + /* escape some charecters according to RFC2254 */ + for (s=q; *s; s++) { + if ((*s == '*') || + (*s == '(') || + (*s == ')') + /* character '\' should be already escaped ! */ + ) { + /* RFC2254 recommendation */ + BIO_printf(mbio, "\\%02X", (int)*s); + continue; + } + BIO_write(mbio, s, 1); + } + + OPENSSL_free(q); + } +#endif + 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'; +#ifdef TRACE_BY_LDAP +fprintf(stderr, "TRACE_BY_LDAP ldaplookup_filter: p=%.512s\n", p); +#endif + +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) { + X509byLDAPerr(X509byLDAP_F_RESULT2STORE, X509byLDAP_R_UNABLE_TO_COUNT_ENTRIES); + ldaplookup_parse_result (ld, res); + 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 + + result = ldaplookup_bind_s(lh->ld); + 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 = ldaplookup_search_s(lh->ld, lh->ldapurl->lud_dn, + LDAP_SCOPE_SUBTREE, filter, (char**)attrs, 0, &res); + 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, (void*)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.5p1/x509_by_ldap.h openssh-4.5p1+x509-6.1/x509_by_ldap.h --- openssh-4.5p1/x509_by_ldap.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/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.5p1/x509_nm_cmp.c openssh-4.5p1+x509-6.1/x509_nm_cmp.c --- openssh-4.5p1/x509_nm_cmp.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/x509_nm_cmp.c 2007-10-21 19:48:55.000000000 +0300 @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2005-2007 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 +#include + +#include "x509store.h" +#include "log.h" +#include "xmalloc.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 !!! + * + * Note pa or pb may contain utf8 characters ! + */ + /* 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_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in) { +/* + * Note before OpenSSL versions 0.7.e method ASN1_STRING_to_UTF8 + * fail when ASN1_STRING is utf8String ! + */ + int tag; + int l; + + if (!in) return(-1); + + tag = M_ASN1_STRING_type(in); + if (tag != V_ASN1_UTF8STRING) { + /*OpenSSL method surprisingly require non-const(!?) ASN1_STRING!*/ + return(ASN1_STRING_to_UTF8(out, in)); + } + + l = M_ASN1_STRING_length(in); + if (out) { + u_char *p; + + if (*out) { + error("ssh_ASN1_STRING_to_UTF8: *out is not NULL"); + return(-1); + } + /* we MUST allocate memory with OPENSSL method! */ + p = OPENSSL_malloc(l + 1); + if (p == NULL) { + fatal("ssh_ASN1_STRING_to_UTF8: out of memory (allocating %d bytes)", (l + 1)); + } + memcpy(p, M_ASN1_STRING_data(in), l); + p[l] = 0; + *out = p; + } + return(l); +} + + +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; + u_char *ua = NULL, *ub = NULL; + + 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)); + /* just in case - see caling methods */ + if (tagB != V_ASN1_PRINTABLESTRING) { + error("ssh_ASN1_PRINTABLESTRING_cmp: b is not PrintableString too"); + return(-1); + } + } + if (tagB != V_ASN1_PRINTABLESTRING) { + debug3("ssh_ASN1_PRINTABLESTRING_cmp: b->type=%d(%.30s) is not PrintableString", tagB, ASN1_tag2str(tagB)); + /* just in case - see caling methods */ + if (tagA != V_ASN1_PRINTABLESTRING) { + error("ssh_ASN1_PRINTABLESTRING_cmp: a is not PrintableString too"); + return(1); + } + } + + if (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); + } else { + /*convert strings to utf8*/ + la = ssh_ASN1_STRING_to_UTF8(&ua, a); + if (la <= 0) { + /*first string is lower in case of error or zero length*/ + n = -1; + goto done; + } + lb = ssh_ASN1_STRING_to_UTF8(&ub, b); + if (lb <= 0) { + /*second string is greater in case of error or zero length*/ + n = 1; + goto done; + } + pa = ua; + pb = ub; + } + + n = ssh_printable_casecmp(pa, la, pb, lb); + +done: + if(ua) OPENSSL_free(ua); + if(ub) OPENSSL_free(ub); +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_ASN1_PRINTABLESTRING_cmp: return %d\n", n); +#endif + return(n); +} + + +/* + * ===================================================================== + * from RFC3280 and oldest 2459: + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1..MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + *..... + * The DirectoryString type is defined as a choice of PrintableString, + * TeletexString, BMPString, UTF8String, and UniversalString. The + * UTF8String encoding is the preferred encoding, and all certificates + * issued after December 31, 2003 MUST use the UTF8String encoding of + * DirectoryString (except as noted below). Until that date, conforming + * CAs MUST choose from the following options when creating a + * distinguished name, including their own: + * (a) if the character set is sufficient, the string MAY be + * represented as a PrintableString; + * (b) failing (a), if the BMPString character set is sufficient the + * string MAY be represented as a BMPString; and + * (c) failing (a) and (b), the string MUST be represented as a + * UTF8String. If (a) or (b) is satisfied, the CA MAY still choose + * to represent the string as a UTF8String. + *..... + * later in RFCs: + * (a) attribute values encoded in different types (e.g., + * PrintableString and BMPString) may be assumed to represent + * different strings; + * (b) attribute values in types other than PrintableString are case + * sensitive (this permits matching of attribute values as binary + * objects); + * (c) attribute values in PrintableString are not case sensitive + * (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and + * (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. + * ===================================================================== + * + * OpenSSH implementation: + * - assume that all DirectoryStrings represent same strings regardless + * of type. When strings are from different types they will be converted + * to utf8 before comparison. + * - when one of the strings is PrintableString they will be compared + * with method that ignore cases and spaces and convert to utf8 + * if necessary. + * + * Note calling method shoud ensure that both strings are + * DirectoryString !!! + */ +static int +ssh_ASN1_DIRECTORYSTRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + int n = -1; + int tagA, tagB; + int la, lb; + const char *pa, *pb; + u_char *ua = NULL, *ub = NULL; + + tagA = M_ASN1_STRING_type(a); + tagB = M_ASN1_STRING_type(b); + + /* just in case of PrintableString - see caling method ;-) */ + if ((tagA == V_ASN1_PRINTABLESTRING) || + (tagB == V_ASN1_PRINTABLESTRING) ) { + /* + * one is PrintableString and we will compare + * according rules for PrintableString. + */ + return(ssh_ASN1_PRINTABLESTRING_cmp(a, b)); + } +/*....*/ + if (tagA == tagB) { + la = M_ASN1_STRING_length(a); + pa = (const char *)M_ASN1_STRING_data(a); + lb = M_ASN1_STRING_length(b); + pb = (const char *)M_ASN1_STRING_data(b); + } else { + /*convert both string to utf8*/ + la = ssh_ASN1_STRING_to_UTF8(&ua, a); + if (la <= 0) { + /*first string is lower in case of error or zero length*/ + n = -1; + goto done; + } + lb = ssh_ASN1_STRING_to_UTF8(&ub, b); + if (lb <= 0) { + /*second string is greater in case of error or zero length*/ + logit("ssh_ASN1_DIRECTORYSTRING_cmp lb=%d", lb); + n = 1; + goto done; + } +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_ASN1_DIRECTORYSTRING_cmp ua='%s'\n", ua); +fprintf(stderr, "ssh_ASN1_DIRECTORYSTRING_cmp ub='%s'\n", ub); +#endif + pa = (const char *)ua; + pb = (const char *)ub; + } + + n = memcmp(pa, pb, (size_t)MIN(la, lb)); +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_ASN1_DIRECTORYSTRING_cmp n=%d, la=%d, lb=%d\n", n, la, lb); +#endif + if (n == 0) n = (lb - la); + +done: + if(ua) OPENSSL_free(ua); + if(ub) OPENSSL_free(ub); +#ifdef SSHX509TEST_DBGCMP +fprintf(stderr, "ssh_ASN1_DIRECTORYSTRING_cmp: return %d\n", n); +#endif + return(n); +} + + +static int/*bool*/ +ssh_is_DirectoryString(const ASN1_STRING* s) { + int tag = M_ASN1_STRING_type(s); + + switch(tag) { + case V_ASN1_T61STRING: /*==V_ASN1_TELETEXSTRING*/ + case V_ASN1_PRINTABLESTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_BMPSTRING: + return(1); + default: + return(0); + } +} + + +/* + * 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, *buf2; + + buf1 = ssh_X509_NAME_oneline(_a); /*fatal on error*/ + buf2 = ssh_X509_NAME_oneline(_b); /*fatal on error*/ + debug3("ssh_X509_NAME_cmp: insufficient entries with nid=%d(%.40s) in second name." + " na=%s, nb=%s", + nid, OBJ_nid2ln(nid), + buf1, buf2); + xfree(buf1); + xfree(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; + } + if (ssh_is_DirectoryString(nvA) && + ssh_is_DirectoryString(nvB)) { + n = ssh_ASN1_DIRECTORYSTRING_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.5p1/x509store.c openssh-4.5p1+x509-6.1/x509store.c --- openssh-4.5p1/x509store.c 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/x509store.c 2007-10-24 00:15:30.000000000 +0300 @@ -0,0 +1,982 @@ +/* + * Copyright (c) 2002-2007 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 +#include "log.h" + +#ifndef SSH_X509STORE_DISABLED +#include + +#include "xmalloc.h" +#include "pathnames.h" +#include "misc.h" +#include +#include +/* 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; + buf = ssh_X509_NAME_oneline(X509_get_subject_name(ctx->current_cert)); /*fatal on error*/ + error("ssh_x509store_cb: subject='%s', error %d at %d depth lookup:%.200s", + buf, + ctx->error, + ctx->error_depth, + X509_verify_cert_error_string(ctx->error)); + xfree(buf); + +#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) { + X509_NAME *issuer, *subject; + + issuer = X509_get_issuer_name(_cert); + subject = X509_get_subject_name(_cert); + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char *buf; + + buf = ssh_X509_NAME_oneline(issuer); /*fatal on error*/ + debug3("ssh_is_selfsigned: issuer='%s'", buf); + xfree(buf); + + buf = ssh_X509_NAME_oneline(subject); /*fatal on error*/ + debug3("ssh_is_selfsigned: subject='%s'", buf); + xfree(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"); + ret = -1; + goto done; + } + + if (get_log_level() >= SYSLOG_LEVEL_DEBUG3) { + char *buf; + buf = ssh_X509_NAME_oneline(X509_get_subject_name(_cert)); /*fatal on error*/ + debug3("ssh_x509cert_check: for '%s'", buf); + xfree(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(); + ret = -1; + goto done; + } + + 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*/ +done: +{ + const char *msg = (ret > 0) ? "trusted" : (ret < 0 ? "error" : "rejected"); + debug3("ssh_x509cert_check: return %d(%s)", ret, msg); +} + return(ret); +} + + +#ifndef SSH_X509STORE_DISABLED +#ifdef SSH_CHECK_REVOKED +static void +ssh_get_namestr_and_hash( + X509_NAME *name, + char **buf, + u_long *hash +) { + if (name == NULL) { + debug("ssh_get_namestr_and_hash: name is NULL"); + if (buf ) *buf = NULL; + if (hash) *hash = 0; /* not correct but :-( */ + return; + } + + if (buf ) *buf = ssh_X509_NAME_oneline(name); /*fatal on error*/ + 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; + 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); /* ;-) */ + } + + ssh_X509_NAME_print(bio, X509_CRL_get_issuer(_crl)); + + 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", 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) + ) { + char *buf; + #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 + ssh_get_namestr_and_hash(X509_get_subject_name(_issuer), &buf, &hash); + error("ssh_check_crl:" + " to verify crl signature key usage 'cRLSign'" + " must present in issuer certificate '%s' with hash=0x%08lx" + , buf, hash + ); + xfree(buf); + 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) { + char *buf; + + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), &buf, &hash); + error("ssh_check_crl: CRL has invalid signature" + ": issuer='%s', hash=0x%08lx" + , buf, hash + ); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + xfree(buf); + 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) { + char *buf; + + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), &buf, &hash); + error("ssh_check_crl: CRL has invalid lastUpdate field" + ": issuer='%s', hash=0x%08lx" + , buf, hash + ); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); + xfree(buf); + return(0); + } + if (k > 0) { + char *buf; + + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), &buf, &hash); + error("ssh_check_crl: CRL is not yet valid" + ": issuer='%s', hash=0x%08lx" + , buf, hash + ); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_NOT_YET_VALID); + xfree(buf); + return(0); + } + + k = X509_cmp_time(X509_CRL_get_nextUpdate(_crl), pcheck_time); + if (k == 0) { + char *buf; + + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), &buf, &hash); + error("ssh_check_crl: CRL has invalid nextUpdate field" + ": issuer='%s', hash=0x%08lx" + , buf, hash + ); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); + xfree(buf); + 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) { + char *buf; + + ssh_get_namestr_and_hash(X509_CRL_get_issuer(_crl), &buf, &hash); + error("ssh_check_crl: CRL is expired" + ": issuer='%s', hash=0x%08lx" + , buf, hash + ); + X509_STORE_CTX_set_error(_ctx, X509_V_ERR_CRL_HAS_EXPIRED); + xfree(buf); + 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 *dn, *ser, *in; + + 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 ...*/ + dn = ssh_X509_NAME_oneline(X509_get_subject_name(_cert)); /*fatal on error*/ + ser = ssh_ASN1_INTEGER_2_string(revoked.serialNumber); + in = ssh_X509_NAME_oneline(X509_CRL_get_issuer (_crl )); /*fatal on error*/ + + error("certificate '%s' with serial '%.40s' revoked from issuer '%s'" + , dn, ser, in); + xfree(dn); + xfree(ser); + xfree(in); + + 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; + + buf = ssh_X509_NAME_oneline(X509_get_issuer_name(cert)); /*fatal on error*/ + debug3("ssh_x509revoked_cb: Issuer: %s", buf); + xfree(buf); + + buf = ssh_X509_NAME_oneline(X509_get_subject_name(cert)); /*fatal on error*/ + debug3("ssh_x509revoked_cb: Subject: %s", buf); + xfree(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.5p1/x509store.h openssh-4.5p1+x509-6.1/x509store.h --- openssh-4.5p1/x509store.h 1970-01-01 02:00:00.000000000 +0200 +++ openssh-4.5p1+x509-6.1/x509store.h 2007-10-04 22:54:04.000000000 +0300 @@ -0,0 +1,123 @@ +#ifndef X509STORE_H +#define X509STORE_H +/* + * Copyright (c) 2002-2007 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 + + +int ssh_X509_NAME_print(BIO* bio, X509_NAME *xn); +char* ssh_X509_NAME_oneline(X509_NAME *xn); + + +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 */