diff -ruN openssh-4.6p1+x509-5.5.2/config.h.in openssh-4.6p1+x509-6.0/config.h.in --- openssh-4.6p1+x509-5.5.2/config.h.in 2007-03-10 09:07:01.000000000 +0200 +++ openssh-4.6p1+x509-6.0/config.h.in 2007-08-07 09: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 diff -ruN openssh-4.6p1+x509-5.5.2/configure openssh-4.6p1+x509-6.0/configure --- openssh-4.6p1+x509-5.5.2/configure 2007-03-10 09:07:02.000000000 +0200 +++ openssh-4.6p1+x509-6.0/configure 2007-08-07 09:06:02.000000000 +0300 @@ -28274,11 +28274,12 @@ { echo "$as_me:$LINENO: checking for Email in X.509 'Distinguished Name'" >&5 echo $ECHO_N "checking for Email in X.509 'Distinguished Name'... $ECHO_C" >&6; } if test "$cross_compiling" = yes; then - { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run test program while cross compiling -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + + { 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. */ @@ -28319,10 +28320,8 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - - { echo "$as_me:$LINENO: result: yes" >&5 + { 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 @@ -28334,7 +28333,6 @@ 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 @@ -28454,6 +28452,424 @@ 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; 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 diff -ruN openssh-4.6p1+x509-5.5.2/configure.ac openssh-4.6p1+x509-6.0/configure.ac --- openssh-4.6p1+x509-5.5.2/configure.ac 2007-03-10 09:07:00.000000000 +0200 +++ openssh-4.6p1+x509-6.0/configure.ac 2007-08-07 09:06:00.000000000 +0300 @@ -3739,8 +3739,8 @@ if test "x$ssh_x509store" = "xyes"; then # Check for Email in X.509 'Distinguished Name' AC_MSG_CHECKING([for Email in X.509 'Distinguished Name']) - AC_TRY_RUN( - [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([ #include int main(void) { @@ -3751,12 +3751,14 @@ exit (0); return (0); } - ], + ])], + [ AC_MSG_RESULT(yes) ], [ - AC_MSG_RESULT(yes) + AC_MSG_RESULT(no) + ssh_x509dn_email="no" ], [ - AC_MSG_RESULT(no) + AC_MSG_WARN([cross compiling: assuming no]) ssh_x509dn_email="no" ] ) @@ -3769,6 +3771,12 @@ [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 diff -ruN openssh-4.6p1+x509-5.5.2/ssh-x509.c openssh-4.6p1+x509-6.0/ssh-x509.c --- openssh-4.6p1+x509-5.5.2/ssh-x509.c 2006-11-08 01:29:21.000000000 +0200 +++ openssh-4.6p1+x509-6.0/ssh-x509.c 2007-08-06 20:43:27.000000000 +0300 @@ -106,13 +106,212 @@ #ifndef SSH_X509STORE_DISABLED +static unsigned long +ssh_hctol(u_char ch) { +#ifndef CHARSET_EBCDIC +/* '0'-'9' = 0x30 - 0x39 */ +/* 'A'-'F' = 0x41 - 0x46 */ +/* 'a'-'f' = 0x61 - 0x66 */ + 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))); + } +#else +# include "ssh_hctol is not implemented for EBCDIC charset" +#endif + + 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" + */ + 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); + } + + 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 char* str, size_t len) { - int ret = 0; +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; + size_t k; - /*this is internal method and we don't check validity of arguments*/ + /*this is internal method and we don't check validity of some arguments*/ - ret = X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (u_char*)str, (int)len, -1, 0); + p = buf; + k = sizeof(buf); + + while ((len > 0) && (k > 0)) { + if (*str == '\0') { + error("ssh_X509_NAME_add_entry_by_NID:" + " unsupported zero(NIL) symbol in name"); + return(0); + } + if (*str == '\\') { + len--; + if (len <= 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " escape sequence without data"); + return(0); + } + + ret = get_escsymbol(++str, len, &ch); + if (ret < 0) return(0); + } else { + ret = UTF8_getc(str, len, &ch); + if(ret < 0) { + error("ssh_X509_NAME_add_entry_by_NID:" + " cannot get next symbol(%.32s)" + , str); + return(0); + } + } + len -= ret; + str += ret; + + /* 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); + } + 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" @@ -172,7 +371,12 @@ ret = 0; break; } - *q = 0; + { + char *s = q; + for(--s; isspace((int)*s) && (s > p); s--) + {/*skip trailing space*/} + *++s = 0; + } nid = OBJ_txt2nid(p); #ifdef SSH_OPENSSL_DN_WITHOUT_EMAIL if (nid == NID_undef) { @@ -195,11 +399,13 @@ break; } + for (; *p && isspace((int)*p); p++) + {/*skip space*/} for (q = token - 1; (q >= p) && isspace((int)*q); q--) {/*skip unexpected \n, etc. from end*/} *++q = 0; - ret = ssh_X509_NAME_add_entry_by_NID(_name, nid, p, (size_t)(q - p)); + ret = ssh_X509_NAME_add_entry_by_NID(_name, nid, (u_char*)p, (size_t)(q - p)); if (!ret) { break; } @@ -436,7 +642,9 @@ int x509key_write_subject2(const Key *key, const char *keyname, FILE *f) { BIO *out; +#if 0 char buf[X509_NAME_MAXLEN]; +#endif if (!x509key_check("x509key_write_subject2", key)) return(0); if (keyname == NULL) return(0); @@ -452,8 +660,12 @@ BIO_puts(out, keyname); BIO_puts(out, " Subject:"); +#if 0 X509_NAME_oneline(X509_get_subject_name(key->x509), buf, sizeof(buf)); BIO_puts(out, buf); +#else + X509_NAME_print_ex(out, X509_get_subject_name(key->x509), 0, SSH_XN_FLAG_ONELINE); +#endif BIO_free_all(out); return(1); @@ -630,8 +842,9 @@ const u_char *data, u_int datalen ) { int ret = -1; - SSHX509KeyAlgs *xkalg; - u_char sigret[256]; + SSHX509KeyAlgs *xkalg = NULL; + int keylen = 0; + u_char *sigret = NULL; u_int siglen; if (!x509key_check("ssh_x509_sign", key)) return(ret); @@ -667,6 +880,16 @@ 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; @@ -674,6 +897,7 @@ 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", @@ -704,6 +928,10 @@ } 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); diff -ruN openssh-4.6p1+x509-5.5.2/ssh-xkalg.c openssh-4.6p1+x509-6.0/ssh-xkalg.c --- openssh-4.6p1+x509-5.5.2/ssh-xkalg.c 2006-09-01 21:24:04.000000000 +0300 +++ openssh-4.6p1+x509-6.0/ssh-xkalg.c 2007-08-06 21:20:15.000000000 +0300 @@ -122,6 +122,7 @@ } +#ifdef HAVE_EVP_MD_CTX_MD_DATA static int init(EVP_MD_CTX *ctx) { return(SHA1_Init(ctx->md_data)); @@ -138,23 +139,38 @@ 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), @@ -446,7 +462,7 @@ p = xkalg->name; dupl = 0; - + for ( k = ssh_xkalg_typeind(type, &xkalg, -1); (k >= 0) && (k < loc); diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/1-cre_cadb.sh openssh-4.6p1+x509-6.0/tests/CA/1-cre_cadb.sh --- openssh-4.6p1+x509-5.5.2/tests/CA/1-cre_cadb.sh 2006-03-12 22:39:08.000000000 +0200 +++ openssh-4.6p1+x509-6.0/tests/CA/1-cre_cadb.sh 2007-02-27 23:22:48.000000000 +0200 @@ -48,6 +48,10 @@ default_crl_days= 30 # how long before next CRL policy = policy_match +# print options (internal use) +name_opt = oneline,-space_eq,-esc_msb # print fine UTF-8 +cert_opt = compatible + EOF } diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/2-cre_cakeys.sh openssh-4.6p1+x509-6.0/tests/CA/2-cre_cakeys.sh --- openssh-4.6p1+x509-5.5.2/tests/CA/2-cre_cakeys.sh 2006-03-12 22:39:54.000000000 +0200 +++ openssh-4.6p1+x509-6.0/tests/CA/2-cre_cakeys.sh 2006-03-12 23:01:31.000000000 +0200 @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# Copyright (c) 2002-2006 Roumen Petrov, Sofia, Bulgaria # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -74,6 +74,7 @@ $OPENSSL req \ -new -x509 \ -config "${SSH_CACFGFILE}" \ + $SSH_DN_UTF8_FLAG \ -days $SSH_CACERTDAYS \ -passin pass:${KEY_PASS} \ -key "${TMPDIR}/${CAKEY_PREFIX}-rsa.key" \ @@ -122,6 +123,7 @@ $OPENSSL req \ -new -x509 \ -config "${SSH_CACFGFILE}" \ + $SSH_DN_UTF8_FLAG \ -days $SSH_CACERTDAYS \ -passin pass:${KEY_PASS} \ -key "${TMPDIR}/${CAKEY_PREFIX}-dsa.key" \ diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/3-cre_certs.sh openssh-4.6p1+x509-6.0/tests/CA/3-cre_certs.sh --- openssh-4.6p1+x509-5.5.2/tests/CA/3-cre_certs.sh 2006-02-16 22:07:11.000000000 +0200 +++ openssh-4.6p1+x509-6.0/tests/CA/3-cre_certs.sh 2007-02-17 20:35:58.000000000 +0200 @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright (c) 2002-2004 Roumen Petrov, Sofia, Bulgaria +# Copyright (c) 2002-2006 Roumen Petrov, Sofia, Bulgaria # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -143,6 +143,7 @@ $OPENSSL req \ -new \ -config "${SSH_CACFGFILE}" \ + $SSH_DN_UTF8_FLAG \ -key "${SSH_BASE_KEY}" \ -passin pass:"" \ -out "${TMPDIR}/${SSH_X509V3_EXTENSIONS}-${type}${subtype}.csr" \ diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/5-cre_ldap.sh openssh-4.6p1+x509-6.0/tests/CA/5-cre_ldap.sh --- openssh-4.6p1+x509-5.5.2/tests/CA/5-cre_ldap.sh 2006-02-16 22:07:07.000000000 +0200 +++ openssh-4.6p1+x509-6.0/tests/CA/5-cre_ldap.sh 2007-02-11 20:52:47.000000000 +0200 @@ -56,17 +56,19 @@ #The organization 'OpenSSH Test Team': -dn: O=${SSH_DN_O},${SSH_LDAP_DC} +# "O=${SSH_DN_O},${SSH_LDAP_DC}" +dn:`utf8base64 "O=${SSH_DN_O},${SSH_LDAP_DC}"` objectclass: organization -o: ${SSH_DN_O} +o:`utf8base64 "${SSH_DN_O}"` st: ${SSH_DN_ST} #The 'OpenSSH Test Team' "CA" organizational units: -dn: OU=${SSH_DN_OU},O=${SSH_DN_O},${SSH_LDAP_DC} +# "OU=${SSH_DN_OU},O=${SSH_DN_O},${SSH_LDAP_DC}" +dn:`utf8base64 "OU=${SSH_DN_OU},O=${SSH_DN_O},${SSH_LDAP_DC}"` objectclass: organizationalUnit -ou: ${SSH_DN_OU} -l: ${SSH_DN_L} +ou:`utf8base64 "${SSH_DN_OU}"` +l:`utf8base64 "${SSH_DN_L}"` st: ${SSH_DN_ST} EOF @@ -76,10 +78,11 @@ cat </dev/null`; 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 @@ -261,4 +273,15 @@ # === +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.6p1+x509-5.5.2/tests/CA/Makefile.in openssh-4.6p1+x509-6.0/tests/CA/Makefile.in --- openssh-4.6p1+x509-5.5.2/tests/CA/Makefile.in 2005-08-10 21:02:59.000000000 +0300 +++ openssh-4.6p1+x509-6.0/tests/CA/Makefile.in 2007-01-27 16:59:16.000000000 +0200 @@ -1,7 +1,7 @@ srcdir=@srcdir@ @OCSP_ON@SSH_OCSP=yes @OCSP_OFF@SSH_OCSP=no -KEYBITS=1024 +RSAKEYBITS=2048 all: @@ -48,7 +48,7 @@ testhostkey_rsa: @echo @echo "generating RSA 'hostkey'" - $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(RSAKEYBITS) -f $@ -N "" testhostkey_rsa-rsa_md5: testhostkey_rsa ca-test/catest-bundle.crt @echo @@ -58,7 +58,7 @@ testhostkey_dsa: @echo @echo "generating DSA 'hostkey'" - $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t dsa -f $@ -N "" testhostkey_dsa-rsa_md5: testhostkey_dsa ca-test/catest-bundle.crt @echo @@ -72,7 +72,7 @@ testid_rsa: @echo @echo "generating RSA 'Identity'" - $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t rsa -b $(RSAKEYBITS) -f $@ -N "" testid_rsa-rsa_md5: testid_rsa ca-test/catest-bundle.crt @echo @@ -82,7 +82,7 @@ testid_dsa: @echo @echo "generating DSA 'Identity'" - $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" + $(TEST_SSH_SSHKEYGEN) -t dsa -f $@ -N "" testid_dsa-rsa_md5: testid_dsa ca-test/catest-bundle.crt @echo @@ -101,7 +101,7 @@ @OCSP_ON@testocsp_rsa: @OCSP_ON@ @echo; echo "generating RSA 'ocspkey'" -@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t rsa -b $(KEYBITS) -f $@ -N "" +@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." @@ -110,7 +110,7 @@ @OCSP_ON@testocsp_dsa: @OCSP_ON@ @echo; echo "generating DSA 'ocspkey'" -@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t dsa -b $(KEYBITS) -f $@ -N "" +@OCSP_ON@ $(TEST_SSH_SSHKEYGEN) -t dsa -f $@ -N "" # === diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/test-agent.sh.inc openssh-4.6p1+x509-6.0/tests/CA/test-agent.sh.inc --- openssh-4.6p1+x509-5.5.2/tests/CA/test-agent.sh.inc 2006-02-05 18:24:05.000000000 +0200 +++ openssh-4.6p1+x509-6.0/tests/CA/test-agent.sh.inc 2007-02-27 22:56:10.000000000 +0200 @@ -107,7 +107,7 @@ # TODO # Note the current script run ssh with -i option, # but ssh check existence of file and when file -# don't exit it is excluded form list of identity +# 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 diff -ruN openssh-4.6p1+x509-5.5.2/tests/CA/test-by_ldap.sh.inc openssh-4.6p1+x509-6.0/tests/CA/test-by_ldap.sh.inc --- openssh-4.6p1+x509-5.5.2/tests/CA/test-by_ldap.sh.inc 2005-08-30 01:43:39.000000000 +0300 +++ openssh-4.6p1+x509-6.0/tests/CA/test-by_ldap.sh.inc 2007-02-12 00:27:13.000000000 +0200 @@ -103,17 +103,18 @@ ( for type in ${SSH_SIGN_TYPES}; do cat < "${AUTHORIZEDKEYSFILE}" runTest "${type} ${subtype} in ${attn}RFC2253${norm} format" "${identity_file}" "" || return $? diff -ruN openssh-4.6p1+x509-5.5.2/x509_by_ldap.c openssh-4.6p1+x509-6.0/x509_by_ldap.c --- openssh-4.6p1+x509-5.5.2/x509_by_ldap.c 2006-09-01 21:23:57.000000000 +0300 +++ openssh-4.6p1+x509-6.0/x509_by_ldap.c 2007-02-13 00:28:14.000000000 +0200 @@ -359,6 +359,28 @@ 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; @@ -388,6 +410,7 @@ 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?) @@ -401,6 +424,32 @@ 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, ")"); } @@ -417,6 +466,9 @@ 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); diff -ruN openssh-4.6p1+x509-5.5.2/x509_nm_cmp.c openssh-4.6p1+x509-6.0/x509_nm_cmp.c --- openssh-4.6p1+x509-5.5.2/x509_nm_cmp.c 2006-09-01 21:23:43.000000000 +0300 +++ openssh-4.6p1+x509-6.0/x509_nm_cmp.c 2007-01-27 18:37:52.000000000 +0200 @@ -71,6 +71,8 @@ * 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++); @@ -103,32 +105,100 @@ 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); + } } - /* TODO when tagA == tagB */ + 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); - /* TODO else */ + } 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, a); + 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 @@ -137,6 +207,140 @@ /* + * ===================================================================== + * 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 (!). @@ -257,6 +461,13 @@ 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; diff -ruN openssh-4.6p1+x509-5.5.2/x509store.h openssh-4.6p1+x509-6.0/x509store.h --- openssh-4.6p1+x509-5.5.2/x509store.h 2006-04-25 22:08:01.000000000 +0300 +++ openssh-4.6p1+x509-6.0/x509store.h 2007-02-27 23:00:42.000000000 +0200 @@ -29,6 +29,10 @@ #define X509_NAME_MAXLEN 512 +#define SSH_XN_FLAG_ONELINE ((XN_FLAG_ONELINE & \ + ~XN_FLAG_SPC_EQ & \ + ~XN_FLAG_SEP_MASK) | \ + XN_FLAG_SEP_COMMA_PLUS) int ssh_x509cert_check(X509 *_cert);