Export EVP_parse_digest_algorithm and add EVP_marshal_digest_algorithm.

Chromium's OCSP code needs the OIDs and we already have them on hand.

Change-Id: Icab012ba4ae15ce029cbfe3ed93f89470137e7f6
Reviewed-on: https://boringssl-review.googlesource.com/20724
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c
index ab7ff59..4b4bb38 100644
--- a/crypto/digest_extra/digest_extra.c
+++ b/crypto/digest_extra/digest_extra.c
@@ -62,7 +62,6 @@
 #include <openssl/bytestring.h>
 #include <openssl/nid.h>
 
-#include "internal.h"
 #include "../internal.h"
 
 
@@ -120,22 +119,22 @@
 static const struct {
   uint8_t oid[9];
   uint8_t oid_len;
-  const EVP_MD *(*md_func) (void);
+  int nid;
 } kMDOIDs[] = {
   // 1.2.840.113549.2.4
-  { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, EVP_md4 },
+  { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, NID_md4 },
   // 1.2.840.113549.2.5
-  { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, EVP_md5 },
+  { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, NID_md5 },
   // 1.3.14.3.2.26
-  { {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, EVP_sha1 },
+  { {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, NID_sha1 },
   // 2.16.840.1.101.3.4.2.1
-  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, EVP_sha256 },
+  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, NID_sha256 },
   // 2.16.840.1.101.3.4.2.2
-  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, EVP_sha384 },
+  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, NID_sha384 },
   // 2.16.840.1.101.3.4.2.3
-  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, EVP_sha512 },
+  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, NID_sha512 },
   // 2.16.840.1.101.3.4.2.4
-  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 },
+  { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, NID_sha224 },
 };
 
 static const EVP_MD *cbs_to_md(const CBS *cbs) {
@@ -143,7 +142,7 @@
     if (CBS_len(cbs) == kMDOIDs[i].oid_len &&
         OPENSSL_memcmp(CBS_data(cbs), kMDOIDs[i].oid, kMDOIDs[i].oid_len) ==
             0) {
-      return kMDOIDs[i].md_func();
+      return EVP_get_digestbynid(kMDOIDs[i].nid);
     }
   }
 
@@ -192,6 +191,41 @@
   return ret;
 }
 
+int EVP_marshal_digest_algorithm(CBB *cbb, const EVP_MD *md) {
+  CBB algorithm, oid, null;
+  if (!CBB_add_asn1(cbb, &algorithm, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT)) {
+    OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  int found = 0;
+  int nid = EVP_MD_type(md);
+  for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) {
+    if (nid == kMDOIDs[i].nid) {
+      if (!CBB_add_bytes(&oid, kMDOIDs[i].oid, kMDOIDs[i].oid_len)) {
+        OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
+        return 0;
+      }
+      found = 1;
+      break;
+    }
+  }
+
+  if (!found) {
+    OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_UNKNOWN_HASH);
+    return 0;
+  }
+
+  if (!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
+      !CBB_flush(cbb)) {
+    OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+
+  return 1;
+}
+
 const EVP_MD *EVP_get_digestbyname(const char *name) {
   for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(nid_to_digest_mapping); i++) {
     const char *short_name = nid_to_digest_mapping[i].short_name;
diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc
index 96fa778..910c731 100644
--- a/crypto/digest_extra/digest_test.cc
+++ b/crypto/digest_extra/digest_test.cc
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 
 #include <openssl/asn1.h>
+#include <openssl/bytestring.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
@@ -31,6 +32,7 @@
 #include <openssl/sha.h>
 
 #include "../internal.h"
+#include "../test/test_util.h"
 
 
 struct MD {
@@ -215,3 +217,44 @@
   EXPECT_EQ(EVP_md5_sha1(), EVP_get_digestbyobj(OBJ_nid2obj(NID_md5_sha1)));
   EXPECT_EQ(EVP_sha1(), EVP_get_digestbyobj(OBJ_nid2obj(NID_sha1)));
 }
+
+TEST(DigestTest, ASN1) {
+  bssl::ScopedCBB cbb;
+  ASSERT_TRUE(CBB_init(cbb.get(), 0));
+  EXPECT_FALSE(EVP_marshal_digest_algorithm(cbb.get(), EVP_md5_sha1()));
+
+  static const uint8_t kSHA256[] = {0x30, 0x0d, 0x06, 0x09, 0x60,
+                                    0x86, 0x48, 0x01, 0x65, 0x03,
+                                    0x04, 0x02, 0x01, 0x05, 0x00};
+  static const uint8_t kSHA256NoParam[] = {0x30, 0x0b, 0x06, 0x09, 0x60,
+                                           0x86, 0x48, 0x01, 0x65, 0x03,
+                                           0x04, 0x02, 0x01};
+  static const uint8_t kSHA256GarbageParam[] = {
+      0x30, 0x0e, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+      0x65, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x2a};
+
+  // Serialize SHA-256.
+  cbb.Reset();
+  ASSERT_TRUE(CBB_init(cbb.get(), 0));
+  ASSERT_TRUE(EVP_marshal_digest_algorithm(cbb.get(), EVP_sha256()));
+  uint8_t *der;
+  size_t der_len;
+  ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
+  bssl::UniquePtr<uint8_t> free_der(der);
+  EXPECT_EQ(Bytes(kSHA256), Bytes(der, der_len));
+
+  // Parse SHA-256.
+  CBS cbs;
+  CBS_init(&cbs, kSHA256, sizeof(kSHA256));
+  EXPECT_EQ(EVP_sha256(), EVP_parse_digest_algorithm(&cbs));
+  EXPECT_EQ(0u, CBS_len(&cbs));
+
+  // Missing parameters are tolerated for compatibility.
+  CBS_init(&cbs, kSHA256NoParam, sizeof(kSHA256NoParam));
+  EXPECT_EQ(EVP_sha256(), EVP_parse_digest_algorithm(&cbs));
+  EXPECT_EQ(0u, CBS_len(&cbs));
+
+  // Garbage parameters are not.
+  CBS_init(&cbs, kSHA256GarbageParam, sizeof(kSHA256GarbageParam));
+  EXPECT_FALSE(EVP_parse_digest_algorithm(&cbs));
+}
diff --git a/crypto/digest_extra/internal.h b/crypto/digest_extra/internal.h
deleted file mode 100644
index 1df200e..0000000
--- a/crypto/digest_extra/internal.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 2017, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-#ifndef OPENSSL_HEADER_DIGEST_EXTRA_INTERNAL_H
-#define OPENSSL_HEADER_DIGEST_EXTRA_INTERNAL_H
-
-#include <openssl/base.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-
-const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs);
-
-
-#if defined(__cplusplus)
-}  // extern C
-#endif
-
-#endif  // OPENSSL_HEADER_DIGEST_EXTRA_INTERNAL
diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c
index ace5f33..b3e2d93 100644
--- a/crypto/pkcs8/pkcs8_x509.c
+++ b/crypto/pkcs8/pkcs8_x509.c
@@ -71,7 +71,6 @@
 
 #include "internal.h"
 #include "../bytestring/internal.h"
-#include "../digest_extra/internal.h"
 #include "../internal.h"
 
 
diff --git a/include/openssl/digest.h b/include/openssl/digest.h
index ad6dd50..9e7f434 100644
--- a/include/openssl/digest.h
+++ b/include/openssl/digest.h
@@ -201,6 +201,23 @@
 #define EVP_MD_FLAG_DIGALGID_ABSENT 2
 
 
+// ASN.1 functions.
+//
+// These functions allow code to parse and serialize AlgorithmIdentifiers for
+// hash functions.
+
+// EVP_parse_digest_algorithm parses an AlgorithmIdentifier structure containing
+// a hash function OID (for example, 2.16.840.1.101.3.4.2.1 is SHA-256) and
+// advances |cbs|. The parameters field may either be omitted or a NULL. It
+// returns the digest function or NULL on error.
+OPENSSL_EXPORT const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs);
+
+// EVP_marshal_digest_algorithm marshals |md| as an AlgorithmIdentifier
+// structure and appends the result to |cbb|. It returns one on success and zero
+// on error.
+OPENSSL_EXPORT int EVP_marshal_digest_algorithm(CBB *cbb, const EVP_MD *md);
+
+
 // Deprecated functions.
 
 // EVP_MD_CTX_copy sets |out|, which must /not/ be initialised, to be a copy of