--- /dev/null
+From ad5a56490ee8a14777c051c90ffe6d38401997bd Mon Sep 17 00:00:00 2001
+From: "Dr. Stephen Henson" <steve@openssl.org>
+Date: Tue, 18 Jul 2006 12:36:19 +0000
+Subject: [PATCH 1/4] Store canonical encodings of Name structures.
+
+---
+ crypto/asn1/x_name.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ crypto/x509/x509.h | 2 +
+ 2 files changed, 202 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/asn1/x_name.c b/crypto/asn1/x_name.c
+index 85be1a6..82ad1f0 100644
+--- a/crypto/asn1/x_name.c
++++ b/crypto/asn1/x_name.c
+@@ -57,6 +57,7 @@
+ */
+
+ #include <stdio.h>
++#include <ctype.h>
+ #include "cryptlib.h"
+ #include <openssl/asn1t.h>
+ #include <openssl/x509.h>
+@@ -71,6 +72,9 @@ static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it);
+ static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it);
+
+ static int x509_name_encode(X509_NAME *a);
++static int x509_name_canon(X509_NAME *a);
++static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in);
++static int i2d_name_canon(STACK *intname, unsigned char **in);
+
+ ASN1_SEQUENCE(X509_NAME_ENTRY) = {
+ ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT),
+@@ -125,6 +129,8 @@ static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it)
+ goto memerr;
+ if ((ret->bytes = BUF_MEM_new()) == NULL)
+ goto memerr;
++ ret->canon_enc = NULL;
++ ret->canon_enclen = 0;
+ ret->modified = 1;
+ *val = (ASN1_VALUE *)ret;
+ return 1;
+@@ -148,6 +154,8 @@ static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+
+ BUF_MEM_free(a->bytes);
+ sk_X509_NAME_ENTRY_pop_free(a->entries, X509_NAME_ENTRY_free);
++ if (a->canon_enc)
++ OPENSSL_free(a->canon_enc);
+ OPENSSL_free(a);
+ *pval = NULL;
+ }
+@@ -163,6 +171,11 @@ static void sk_internal_free(void *a)
+ sk_free(a);
+ }
+
++static void canon_free(void *a)
++{
++ sk_X509_NAME_ENTRY_pop_free(a, X509_NAME_ENTRY_free);
++}
++
+ static int x509_name_ex_d2i(ASN1_VALUE **val, const unsigned char **in,
+ long len, const ASN1_ITEM *it, int tag,
+ int aclass, char opt, ASN1_TLC *ctx)
+@@ -214,6 +227,9 @@ static int x509_name_ex_d2i(ASN1_VALUE **val, const unsigned char **in,
+ sk_X509_NAME_ENTRY_free(entries);
+ }
+ sk_free(intname.s);
++ ret = x509_name_canon(nm.x);
++ if (!ret)
++ goto err;
+ nm.x->modified = 0;
+ *val = nm.a;
+ *in = p;
+@@ -231,9 +247,12 @@ static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out,
+ int ret;
+ X509_NAME *a = (X509_NAME *)*val;
+ if (a->modified) {
+- ret = x509_name_encode((X509_NAME *)a);
++ ret = x509_name_encode(a);
+ if (ret < 0)
+ return ret;
++ ret = x509_name_canon(a);
++ if(ret < 0)
++ return ret;
+ }
+ ret = a->bytes->length;
+ if (out != NULL) {
+@@ -288,6 +307,186 @@ static int x509_name_encode(X509_NAME *a)
+ return -1;
+ }
+
++/* This function generates the canonical encoding of the Name structure.
++ * In it all strings are converted to UTF8, leading, trailing and
++ * multiple spaces collapsed, converted to lower case and the leading
++ * SEQUENCE header removed.
++ *
++ * In future we could also normalize the UTF8 too.
++ *
++ * By doing this comparison of Name structures can be rapidly
++ * perfomed by just using memcmp() of the canonical encoding.
++ * By omitting the leading SEQUENCE name constraints of type
++ * dirName can also be checked with a simple memcmp().
++ */
++
++static int x509_name_canon(X509_NAME *a)
++ {
++ unsigned char *p;
++ STACK *intname = NULL;
++ STACK_OF(X509_NAME_ENTRY) *entries = NULL;
++ X509_NAME_ENTRY *entry, *tmpentry;
++ int i, set = -1, ret = 0;
++ if (a->canon_enc)
++ {
++ OPENSSL_free(a->canon_enc);
++ a->canon_enc = NULL;
++ }
++ intname = sk_new_null();
++ if(!intname)
++ goto err;
++ for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++)
++ {
++ entry = sk_X509_NAME_ENTRY_value(a->entries, i);
++ if(entry->set != set)
++ {
++ entries = sk_X509_NAME_ENTRY_new_null();
++ if(!entries)
++ goto err;
++ if(!sk_push(intname, (char *)entries))
++ goto err;
++ set = entry->set;
++ }
++ tmpentry = X509_NAME_ENTRY_new();
++ tmpentry->object = OBJ_dup(entry->object);
++ if (!asn1_string_canon(tmpentry->value, entry->value))
++ goto err;
++ if(!sk_X509_NAME_ENTRY_push(entries, tmpentry))
++ goto err;
++ tmpentry = NULL;
++ }
++
++ /* Finally generate encoding */
++
++ a->canon_enclen = i2d_name_canon(intname, NULL);
++
++ p = OPENSSL_malloc(a->canon_enclen);
++
++ if (!p)
++ goto err;
++
++ a->canon_enc = p;
++
++ i2d_name_canon(intname, &p);
++
++ ret = 1;
++
++ err:
++
++ if (tmpentry)
++ X509_NAME_ENTRY_free(tmpentry);
++ if (intname)
++ sk_pop_free(intname, canon_free);
++ return ret;
++ }
++
++/* Bitmap of all the types of string that will be canonicalized. */
++
++#define ASN1_MASK_CANON \
++ (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \
++ | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \
++ | B_ASN1_VISIBLESTRING)
++
++
++static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in)
++ {
++ unsigned char *to, *from;
++ int len, i;
++
++ /* If type not in bitmask just copy string across */
++ if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON))
++ {
++ out->type = in->type;
++ if (!ASN1_STRING_set(out, in->data, in->length))
++ return 0;
++ }
++
++ out->type = V_ASN1_UTF8STRING;
++ out->length = ASN1_STRING_to_UTF8(&out->data, in);
++ if (out->length == -1)
++ return 0;
++
++ to = out->data;
++ from = to;
++
++ len = out->length;
++
++ /* Convert string in place to canonical form.
++ * Ultimately we may need to handle a wider range of characters
++ * but for now ignore anything with MSB set and rely on the
++ * isspace() and tolower() functions.
++ */
++
++ /* Ignore leading spaces */
++ while((len > 0) && !(*from & 0x80) && isspace(*from))
++ {
++ from++;
++ len--;
++ }
++
++ to = from + len - 1;
++
++ /* Ignore trailing spaces */
++ while ((len > 0) && !(*to & 0x80) && isspace(*to))
++ {
++ to--;
++ len--;
++ }
++
++ to = out->data;
++
++ i = 0;
++ while(i < len)
++ {
++ /* If MSB set just copy across */
++ if (*from & 0x80)
++ *to++ = *from++;
++ /* Collapse multiple spaces */
++ else if (isspace(*from))
++ {
++ /* Copy one space across */
++ *to++ = ' ';
++ /* Ignore subsequent spaces. Note: don't need to
++ * check len here because we know the last
++ * character is a non-space so we can't overflow.
++ */
++ do
++ {
++ from++;
++ i++;
++ }
++ while(!(*from & 0x80) && isspace(*from));
++ }
++ else
++ {
++ *to++ = tolower(*from++);
++ i++;
++ }
++ }
++
++ out->length = to - out->data;
++
++ return 1;
++
++ }
++
++static int i2d_name_canon(STACK *intname, unsigned char **in)
++ {
++ int i, len, ltmp;
++ ASN1_VALUE *v;
++ len = 0;
++ for (i = 0; i < sk_num(intname); i++)
++ {
++ v = (ASN1_VALUE *)sk_value(intname, i);
++ ltmp = ASN1_item_ex_i2d(&v, in,
++ ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1);
++ if (ltmp < 0)
++ return ltmp;
++ len += ltmp;
++ }
++ return len;
++ }
++
+ int X509_NAME_set(X509_NAME **xn, X509_NAME *name)
+ {
+ X509_NAME *in;
+diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
+index 51cccbf..76efbd8 100644
+--- a/crypto/x509/x509.h
++++ b/crypto/x509/x509.h
+@@ -185,6 +185,8 @@ struct X509_name_st {
+ char *bytes;
+ # endif
+ unsigned long hash; /* Keep the hash around for lookups */
++ unsigned char *canon_enc;
++ int canon_enclen;
+ } /* X509_NAME */ ;
+
+ DECLARE_STACK_OF(X509_NAME)
+--
+1.9.1
+
--- /dev/null
+From 2ddc9de2d172c818b366153c764383d8ff00fefa Mon Sep 17 00:00:00 2001
+From: notaz <notasas@gmail.com>
+Date: Sun, 26 Jul 2015 21:09:38 +0300
+Subject: [PATCH 2/4] canonical related backports from 1.0.0s
+
+---
+ crypto/asn1/x_name.c | 339 +++++++++++++++++++++++++--------------------------
+ 1 file changed, 168 insertions(+), 171 deletions(-)
+
+diff --git a/crypto/asn1/x_name.c b/crypto/asn1/x_name.c
+index 82ad1f0..5fa51bd 100644
+--- a/crypto/asn1/x_name.c
++++ b/crypto/asn1/x_name.c
+@@ -307,185 +307,182 @@ static int x509_name_encode(X509_NAME *a)
+ return -1;
+ }
+
+-/* This function generates the canonical encoding of the Name structure.
+- * In it all strings are converted to UTF8, leading, trailing and
+- * multiple spaces collapsed, converted to lower case and the leading
+- * SEQUENCE header removed.
+- *
+- * In future we could also normalize the UTF8 too.
+- *
+- * By doing this comparison of Name structures can be rapidly
+- * perfomed by just using memcmp() of the canonical encoding.
+- * By omitting the leading SEQUENCE name constraints of type
+- * dirName can also be checked with a simple memcmp().
++/*
++ * This function generates the canonical encoding of the Name structure. In
++ * it all strings are converted to UTF8, leading, trailing and multiple
++ * spaces collapsed, converted to lower case and the leading SEQUENCE header
++ * removed. In future we could also normalize the UTF8 too. By doing this
++ * comparison of Name structures can be rapidly perfomed by just using
++ * memcmp() of the canonical encoding. By omitting the leading SEQUENCE name
++ * constraints of type dirName can also be checked with a simple memcmp().
+ */
+
+ static int x509_name_canon(X509_NAME *a)
+- {
+- unsigned char *p;
+- STACK *intname = NULL;
+- STACK_OF(X509_NAME_ENTRY) *entries = NULL;
+- X509_NAME_ENTRY *entry, *tmpentry;
+- int i, set = -1, ret = 0;
+- if (a->canon_enc)
+- {
+- OPENSSL_free(a->canon_enc);
+- a->canon_enc = NULL;
+- }
+- intname = sk_new_null();
+- if(!intname)
+- goto err;
+- for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++)
+- {
+- entry = sk_X509_NAME_ENTRY_value(a->entries, i);
+- if(entry->set != set)
+- {
+- entries = sk_X509_NAME_ENTRY_new_null();
+- if(!entries)
+- goto err;
+- if(!sk_push(intname, (char *)entries))
+- goto err;
+- set = entry->set;
+- }
+- tmpentry = X509_NAME_ENTRY_new();
+- tmpentry->object = OBJ_dup(entry->object);
+- if (!asn1_string_canon(tmpentry->value, entry->value))
+- goto err;
+- if(!sk_X509_NAME_ENTRY_push(entries, tmpentry))
+- goto err;
+- tmpentry = NULL;
+- }
+-
+- /* Finally generate encoding */
+-
+- a->canon_enclen = i2d_name_canon(intname, NULL);
+-
+- p = OPENSSL_malloc(a->canon_enclen);
+-
+- if (!p)
+- goto err;
+-
+- a->canon_enc = p;
+-
+- i2d_name_canon(intname, &p);
+-
+- ret = 1;
+-
+- err:
+-
+- if (tmpentry)
+- X509_NAME_ENTRY_free(tmpentry);
+- if (intname)
+- sk_pop_free(intname, canon_free);
+- return ret;
+- }
++{
++ unsigned char *p;
++ STACK *intname = NULL;
++ STACK_OF(X509_NAME_ENTRY) *entries = NULL;
++ X509_NAME_ENTRY *entry, *tmpentry = NULL;
++ int i, set = -1, ret = 0;
++
++ if (a->canon_enc) {
++ OPENSSL_free(a->canon_enc);
++ a->canon_enc = NULL;
++ }
++ /* Special case: empty X509_NAME => null encoding */
++ if (sk_X509_NAME_ENTRY_num(a->entries) == 0) {
++ a->canon_enclen = 0;
++ return 1;
++ }
++ intname = sk_new_null();
++ if (!intname)
++ goto err;
++ for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
++ entry = sk_X509_NAME_ENTRY_value(a->entries, i);
++ if (entry->set != set) {
++ entries = sk_X509_NAME_ENTRY_new_null();
++ if (!entries)
++ goto err;
++ if (!sk_push(intname, (char *)entries))
++ goto err;
++ set = entry->set;
++ }
++ tmpentry = X509_NAME_ENTRY_new();
++ tmpentry->object = OBJ_dup(entry->object);
++ if (!asn1_string_canon(tmpentry->value, entry->value))
++ goto err;
++ if (!sk_X509_NAME_ENTRY_push(entries, tmpentry))
++ goto err;
++ tmpentry = NULL;
++ }
++
++ /* Finally generate encoding */
++
++ a->canon_enclen = i2d_name_canon(intname, NULL);
++
++ p = OPENSSL_malloc(a->canon_enclen);
++
++ if (!p)
++ goto err;
++
++ a->canon_enc = p;
++
++ i2d_name_canon(intname, &p);
++
++ ret = 1;
++
++ err:
++
++ if (tmpentry)
++ X509_NAME_ENTRY_free(tmpentry);
++ if (intname)
++ sk_pop_free(intname, canon_free);
++ return ret;
++}
+
+ /* Bitmap of all the types of string that will be canonicalized. */
+
+-#define ASN1_MASK_CANON \
+- (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \
+- | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \
+- | B_ASN1_VISIBLESTRING)
+-
++#define ASN1_MASK_CANON \
++ (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \
++ | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \
++ | B_ASN1_VISIBLESTRING)
+
+ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in)
+- {
+- unsigned char *to, *from;
+- int len, i;
+-
+- /* If type not in bitmask just copy string across */
+- if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON))
+- {
+- out->type = in->type;
+- if (!ASN1_STRING_set(out, in->data, in->length))
+- return 0;
+- }
+-
+- out->type = V_ASN1_UTF8STRING;
+- out->length = ASN1_STRING_to_UTF8(&out->data, in);
+- if (out->length == -1)
+- return 0;
+-
+- to = out->data;
+- from = to;
+-
+- len = out->length;
+-
+- /* Convert string in place to canonical form.
+- * Ultimately we may need to handle a wider range of characters
+- * but for now ignore anything with MSB set and rely on the
+- * isspace() and tolower() functions.
+- */
+-
+- /* Ignore leading spaces */
+- while((len > 0) && !(*from & 0x80) && isspace(*from))
+- {
+- from++;
+- len--;
+- }
+-
+- to = from + len - 1;
+-
+- /* Ignore trailing spaces */
+- while ((len > 0) && !(*to & 0x80) && isspace(*to))
+- {
+- to--;
+- len--;
+- }
+-
+- to = out->data;
+-
+- i = 0;
+- while(i < len)
+- {
+- /* If MSB set just copy across */
+- if (*from & 0x80)
+- *to++ = *from++;
+- /* Collapse multiple spaces */
+- else if (isspace(*from))
+- {
+- /* Copy one space across */
+- *to++ = ' ';
+- /* Ignore subsequent spaces. Note: don't need to
+- * check len here because we know the last
+- * character is a non-space so we can't overflow.
+- */
+- do
+- {
+- from++;
+- i++;
+- }
+- while(!(*from & 0x80) && isspace(*from));
+- }
+- else
+- {
+- *to++ = tolower(*from++);
+- i++;
+- }
+- }
+-
+- out->length = to - out->data;
+-
+- return 1;
+-
+- }
+-
+-static int i2d_name_canon(STACK *intname, unsigned char **in)
+- {
+- int i, len, ltmp;
+- ASN1_VALUE *v;
+- len = 0;
+- for (i = 0; i < sk_num(intname); i++)
+- {
+- v = (ASN1_VALUE *)sk_value(intname, i);
+- ltmp = ASN1_item_ex_i2d(&v, in,
+- ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1);
+- if (ltmp < 0)
+- return ltmp;
+- len += ltmp;
+- }
+- return len;
+- }
++{
++ unsigned char *to, *from;
++ int len, i;
++
++ /* If type not in bitmask just copy string across */
++ if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) {
++ if (!ASN1_STRING_set(out, in->data, in->length))
++ return 0;
++ return 1;
++ }
++
++ out->type = V_ASN1_UTF8STRING;
++ out->length = ASN1_STRING_to_UTF8(&out->data, in);
++ if (out->length == -1)
++ return 0;
++
++ to = out->data;
++ from = to;
++
++ len = out->length;
++
++ /*
++ * Convert string in place to canonical form. Ultimately we may need to
++ * handle a wider range of characters but for now ignore anything with
++ * MSB set and rely on the isspace() and tolower() functions.
++ */
++
++ /* Ignore leading spaces */
++ while ((len > 0) && !(*from & 0x80) && isspace(*from)) {
++ from++;
++ len--;
++ }
++
++ to = from + len - 1;
++
++ /* Ignore trailing spaces */
++ while ((len > 0) && !(*to & 0x80) && isspace(*to)) {
++ to--;
++ len--;
++ }
++
++ to = out->data;
++
++ i = 0;
++ while (i < len) {
++ /* If MSB set just copy across */
++ if (*from & 0x80) {
++ *to++ = *from++;
++ i++;
++ }
++ /* Collapse multiple spaces */
++ else if (isspace(*from)) {
++ /* Copy one space across */
++ *to++ = ' ';
++ /*
++ * Ignore subsequent spaces. Note: don't need to check len here
++ * because we know the last character is a non-space so we can't
++ * overflow.
++ */
++ do {
++ from++;
++ i++;
++ }
++ while (!(*from & 0x80) && isspace(*from));
++ } else {
++ *to++ = tolower(*from);
++ from++;
++ i++;
++ }
++ }
++
++ out->length = to - out->data;
++
++ return 1;
++
++}
++
++static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * _intname,
++ unsigned char **in)
++{
++ int i, len, ltmp;
++ ASN1_VALUE *v;
++ STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname;
++
++ len = 0;
++ for (i = 0; i < sk_ASN1_VALUE_num(intname); i++) {
++ v = sk_ASN1_VALUE_value(intname, i);
++ ltmp = ASN1_item_ex_i2d(&v, in,
++ ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1);
++ if (ltmp < 0)
++ return ltmp;
++ len += ltmp;
++ }
++ return len;
++}
+
+ int X509_NAME_set(X509_NAME **xn, X509_NAME *name)
+ {
+--
+1.9.1
+
--- /dev/null
+From 77649551e11dfe9f7d6dc5154abc4d1ab59726e2 Mon Sep 17 00:00:00 2001
+From: "Dr. Stephen Henson" <steve@openssl.org>
+Date: Thu, 15 Jan 2009 13:22:39 +0000
+Subject: [PATCH 3/4] Update certificate hash line format to handle canonical
+ format and avoid MD5 dependency.
+
+---
+ crypto/x509/x509.h | 1 +
+ crypto/x509/x509_cmp.c | 17 ++++++++++++++++-
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
+index 76efbd8..2f8d271 100644
+--- a/crypto/x509/x509.h
++++ b/crypto/x509/x509.h
+@@ -1051,6 +1051,7 @@ unsigned long X509_subject_name_hash(X509 *x);
+ int X509_cmp(const X509 *a, const X509 *b);
+ int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
+ unsigned long X509_NAME_hash(X509_NAME *x);
++unsigned long X509_NAME_hash_old(X509_NAME *x);
+
+ int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
+ # ifndef OPENSSL_NO_FP_API
+diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
+index de66d37..150146e 100644
+--- a/crypto/x509/x509_cmp.c
++++ b/crypto/x509/x509_cmp.c
+@@ -310,12 +310,27 @@ int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
+ return (0);
+ }
+
++unsigned long X509_NAME_hash(X509_NAME *x)
++{
++ unsigned long ret=0;
++ unsigned char md[16];
++
++ /* Make sure X509_NAME structure contains valid cached encoding */
++ i2d_X509_NAME(x,NULL);
++ EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(), NULL);
++
++ ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)|
++ ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
++ )&0xffffffffL;
++ return(ret);
++}
++
+ #ifndef OPENSSL_NO_MD5
+ /*
+ * I now DER encode the name and hash it. Since I cache the DER encoding,
+ * this is reasonably efficient.
+ */
+-unsigned long X509_NAME_hash(X509_NAME *x)
++unsigned long X509_NAME_hash_old(X509_NAME *x)
+ {
+ unsigned long ret = 0;
+ unsigned char md[16];
+--
+1.9.1
+
--- /dev/null
+From 8fff84a70d9b61e511c5ce9927f8bfbdc26f4df3 Mon Sep 17 00:00:00 2001
+From: "Dr. Stephen Henson" <steve@openssl.org>
+Date: Tue, 12 Jan 2010 17:29:34 +0000
+Subject: [PATCH 4/4] PR: 2136 Submitted by: Willy Weisz
+ <weisz@vcpc.univie.ac.at>
+
+Add options to output hash using older algorithm compatible with OpenSSL
+versions before 1.0.0
+---
+ apps/x509.c | 25 +++++++++++++++++++++++++
+ crypto/x509/x509.h | 5 +++++
+ crypto/x509/x509_cmp.c | 14 ++++++++++++++
+ doc/apps/x509.pod | 16 ++++++++++++++++
+ 4 files changed, 60 insertions(+)
+
+diff --git a/apps/x509.c b/apps/x509.c
+index d23f071..af49981 100644
+--- a/apps/x509.c
++++ b/apps/x509.c
+@@ -99,7 +99,13 @@ static const char *x509_usage[] = {
+ " -passin arg - private key password source\n",
+ " -serial - print serial number value\n",
+ " -subject_hash - print subject hash value\n",
++#ifndef OPENSSL_NO_MD5
++ " -subject_hash_old - print old-style (MD5) subject hash value\n",
++#endif
+ " -issuer_hash - print issuer hash value\n",
++#ifndef OPENSSL_NO_MD5
++ " -issuer_hash_old - print old-style (MD5) issuer hash value\n",
++#endif
+ " -hash - synonym for -subject_hash\n",
+ " -subject - print subject DN\n",
+ " -issuer - print issuer DN\n",
+@@ -180,6 +186,9 @@ int MAIN(int argc, char **argv)
+ 0, enddate = 0;
+ int next_serial = 0;
+ int subject_hash = 0, issuer_hash = 0, ocspid = 0;
++#ifndef OPENSSL_NO_MD5
++ int subject_hash_old=0,issuer_hash_old=0;
++#endif
+ int noout = 0, sign_flag = 0, CA_flag = 0, CA_createserial = 0, email = 0;
+ int ocsp_uri = 0;
+ int trustout = 0, clrtrust = 0, clrreject = 0, aliasout = 0, clrext = 0;
+@@ -376,8 +385,16 @@ int MAIN(int argc, char **argv)
+ else if (strcmp(*argv, "-hash") == 0
+ || strcmp(*argv, "-subject_hash") == 0)
+ subject_hash = ++num;
++#ifndef OPENSSL_NO_MD5
++ else if (strcmp(*argv,"-subject_hash_old") == 0)
++ subject_hash_old= ++num;
++#endif
+ else if (strcmp(*argv, "-issuer_hash") == 0)
+ issuer_hash = ++num;
++#ifndef OPENSSL_NO_MD5
++ else if (strcmp(*argv,"-issuer_hash_old") == 0)
++ issuer_hash_old= ++num;
++#endif
+ else if (strcmp(*argv, "-subject") == 0)
+ subject = ++num;
+ else if (strcmp(*argv, "-issuer") == 0)
+@@ -687,8 +704,16 @@ int MAIN(int argc, char **argv)
+ BIO_puts(STDout, "<No Alias>\n");
+ } else if (subject_hash == i) {
+ BIO_printf(STDout, "%08lx\n", X509_subject_name_hash(x));
++#ifndef OPENSSL_NO_MD5
++ } else if (subject_hash_old == i) {
++ BIO_printf(STDout,"%08lx\n",X509_subject_name_hash_old(x));
++#endif
+ } else if (issuer_hash == i) {
+ BIO_printf(STDout, "%08lx\n", X509_issuer_name_hash(x));
++#ifndef OPENSSL_NO_MD5
++ } else if (issuer_hash_old == i) {
++ BIO_printf(STDout,"%08lx\n",X509_issuer_name_hash_old(x));
++#endif
+ } else if (pprint == i) {
+ X509_PURPOSE *ptmp;
+ int j;
+diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
+index 2f8d271..7ac4dbe 100644
+--- a/crypto/x509/x509.h
++++ b/crypto/x509/x509.h
+@@ -1048,6 +1048,11 @@ unsigned long X509_issuer_name_hash(X509 *a);
+ int X509_subject_name_cmp(const X509 *a, const X509 *b);
+ unsigned long X509_subject_name_hash(X509 *x);
+
++#ifndef OPENSSL_NO_MD5
++unsigned long X509_issuer_name_hash_old(X509 *a);
++unsigned long X509_subject_name_hash_old(X509 *x);
++#endif
++
+ int X509_cmp(const X509 *a, const X509 *b);
+ int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
+ unsigned long X509_NAME_hash(X509_NAME *x);
+diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
+index 150146e..8c587f9 100644
+--- a/crypto/x509/x509_cmp.c
++++ b/crypto/x509/x509_cmp.c
+@@ -127,6 +127,13 @@ unsigned long X509_issuer_name_hash(X509 *x)
+ return (X509_NAME_hash(x->cert_info->issuer));
+ }
+
++#ifndef OPENSSL_NO_MD5
++unsigned long X509_issuer_name_hash_old(X509 *x)
++ {
++ return(X509_NAME_hash_old(x->cert_info->issuer));
++ }
++#endif
++
+ X509_NAME *X509_get_subject_name(X509 *a)
+ {
+ return (a->cert_info->subject);
+@@ -142,6 +149,13 @@ unsigned long X509_subject_name_hash(X509 *x)
+ return (X509_NAME_hash(x->cert_info->subject));
+ }
+
++#ifndef OPENSSL_NO_MD5
++unsigned long X509_subject_name_hash_old(X509 *x)
++ {
++ return(X509_NAME_hash_old(x->cert_info->subject));
++ }
++#endif
++
+ #ifndef OPENSSL_NO_SHA
+ /*
+ * Compare two certificates: they must be identical for this to work. NB:
+diff --git a/doc/apps/x509.pod b/doc/apps/x509.pod
+index eba7067..3d18a68 100644
+--- a/doc/apps/x509.pod
++++ b/doc/apps/x509.pod
+@@ -165,6 +165,16 @@ outputs the OCSP hash values for the subject name and public key.
+
+ synonym for "-subject_hash" for backward compatibility reasons.
+
++=item B<-subject_hash_old>
++
++outputs the "hash" of the certificate subject name using the older algorithm
++as used by OpenSSL versions before 1.0.0.
++
++=item B<-issuer_hash_old>
++
++outputs the "hash" of the certificate issuer name using the older algorithm
++as used by OpenSSL versions before 1.0.0.
++
+ =item B<-subject>
+
+ outputs the subject name.
+@@ -847,4 +857,10 @@ L<gendsa(1)|gendsa(1)>, L<verify(1)|verify(1)>
+
+ Before OpenSSL 0.9.8, the default digest for RSA keys was MD5.
+
++The hash algorithm used in the B<-subject_hash> and B<-issuer_hash> options
++before OpenSSL 1.0.0 was based on the deprecated MD5 algorithm and the encoding
++of the distinguished name. In OpenSSL 1.0.0 and later it is based on a
++canonical version of the DN using SHA1. This means that any directories using
++the old form must have their links rebuilt using B<c_rehash> or similar.
++
+ =cut
+--
+1.9.1
+
--- /dev/null
+diff --git a/tools/c_rehash.in b/tools/c_rehash.in
+index da74501..97f6e2b 100644
+--- a/tools/c_rehash.in
++++ b/tools/c_rehash.in
+@@ -71,6 +71,7 @@ sub hash_dir {
+ }
+ }
+ link_hash_cert($fname) if($cert);
++ link_hash_cert_old($fname) if($cert);
+ link_hash_crl($fname) if($crl);
+ }
+ }
+@@ -104,8 +105,9 @@ sub check_file {
+
+ sub link_hash_cert {
+ my $fname = $_[0];
++ my $hashopt = $_[1] || '-subject_hash';
+ $fname =~ s/'/'\\''/g;
+- my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname'`;
++ my ($hash, $fprint) = `"$openssl" x509 $hashopt -fingerprint -noout -in "$fname"`;
+ chomp $hash;
+ chomp $fprint;
+ $fprint =~ s/^.*=//;
+@@ -131,6 +133,10 @@ sub link_hash_cert {
+ $hashlist{$hash} = $fprint;
+ }
+
++sub link_hash_cert_old {
++ link_hash_cert($_[0], '-subject_hash_old');
++}
++
+ # Same as above except for a CRL. CRL links are of the form <hash>.r<n>
+
+ sub link_hash_crl {
Upstream-Status: Backport [debian]
-Index: openssl-0.9.8k/tools/c_rehash.in
-===================================================================
---- openssl-0.9.8k.orig/tools/c_rehash.in 2002-10-11 22:31:27.000000000 +0200
-+++ openssl-0.9.8k/tools/c_rehash.in 2009-07-19 11:36:26.000000000 +0200
-@@ -59,12 +59,15 @@
+diff --git a/tools/c_rehash.in b/tools/c_rehash.in
+index 8b6d3f5..da74501 100644
+--- a/tools/c_rehash.in
++++ b/tools/c_rehash.in
+@@ -60,12 +60,15 @@ sub hash_dir {
}
}
closedir DIR;
}
link_hash_cert($fname) if($cert);
link_hash_crl($fname) if($crl);
-@@ -102,6 +105,9 @@
+@@ -134,6 +137,9 @@ sub link_hash_crl {
my $fname = $_[0];
$fname =~ s/'/'\\''/g;
- my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname'`;
+ my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`;
+ if(!$hash || !fprint) {
-+ ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname' -inform der`;
++ ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname' -inform der`;
+ }
chomp $hash;
chomp $fprint;
require openssl.inc
-PR = "r0"
+PR = "r1"
SRC_URI += "file://debian/ca.patch;patch=1 \
file://debian/config-hurd.patch;apply=no \
file://debian/debian-targets.patch;patch=1 \
file://shared-libs.patch;patch=1 \
file://parallel-make-fix.patch;patch=1"
+# openssl x509 -subject_hash_old support (and -subject_hash change)
+SRC_URI += "file://0001-Store-canonical-encodings-of-Name-structures.patch;patch=1 \
+ file://0002-canonical-related-backports-from-1.0.0s.patch;patch=1 \
+ file://0003-Update-certificate-hash-line-format-to-handle-canoni.patch;patch=1 \
+ file://0004-PR-2136-Submitted-by-Willy-Weisz-weisz-vcpc.univie.a.patch;patch=1 \
+ file://c_rehash-compat.patch;patch=1"
+
SRC_URI[md5sum] = "0a912b6623ac95a8627ea2bd0e0abf1b"
SRC_URI[sha256sum] = "06500060639930e471050474f537fcd28ec934af92ee282d78b52460fbe8f580"