Add |OBJ_NAME_do_all_sorted|.

This another of those functions that tries to turn C into Python. In
this case, implement it in terms of the similar functions in EVP so that
at least we only have one list of things.

This makes life with nmap easier.

Change-Id: I6d01c43f062748d4ba7d7020587c286322e610bb
Reviewed-on: https://boringssl-review.googlesource.com/7403
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/decrepit/CMakeLists.txt b/decrepit/CMakeLists.txt
index 730d794..d18d223 100644
--- a/decrepit/CMakeLists.txt
+++ b/decrepit/CMakeLists.txt
@@ -4,6 +4,7 @@
 add_subdirectory(des)
 add_subdirectory(dsa)
 add_subdirectory(evp)
+add_subdirectory(obj)
 add_subdirectory(rc4)
 add_subdirectory(ripemd)
 add_subdirectory(rsa)
@@ -19,6 +20,7 @@
   $<TARGET_OBJECTS:des_decrepit>
   $<TARGET_OBJECTS:dsa_decrepit>
   $<TARGET_OBJECTS:evp_decrepit>
+  $<TARGET_OBJECTS:obj_decrepit>
   $<TARGET_OBJECTS:rc4_decrepit>
   $<TARGET_OBJECTS:ripemd_decrepit>
   $<TARGET_OBJECTS:rsa_decrepit>
diff --git a/decrepit/obj/CMakeLists.txt b/decrepit/obj/CMakeLists.txt
new file mode 100644
index 0000000..caaecd3
--- /dev/null
+++ b/decrepit/obj/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(../../include)
+
+add_library(
+  obj_decrepit
+
+  OBJECT
+
+  obj_decrepit.c
+)
diff --git a/decrepit/obj/obj_decrepit.c b/decrepit/obj/obj_decrepit.c
new file mode 100644
index 0000000..b1255c7
--- /dev/null
+++ b/decrepit/obj/obj_decrepit.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2016, 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. */
+
+#include <openssl/obj.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+
+struct wrapped_callback {
+  void (*callback)(const OBJ_NAME *, void *arg);
+  void *arg;
+};
+
+static void cipher_callback(const EVP_CIPHER *cipher, const char *name,
+                            const char *unused, void *arg) {
+  const struct wrapped_callback *wrapped = (struct wrapped_callback *)arg;
+  OBJ_NAME obj_name;
+
+  memset(&name, 0, sizeof(name));
+  obj_name.type = OBJ_NAME_TYPE_CIPHER_METH;
+  obj_name.name = name;
+
+  wrapped->callback(&obj_name, wrapped->arg);
+}
+
+static void md_callback(const EVP_MD *md, const char *name, const char *unused,
+                        void *arg) {
+  const struct wrapped_callback *wrapped = (struct wrapped_callback*) arg;
+  OBJ_NAME obj_name;
+
+  memset(&name, 0, sizeof(name));
+  obj_name.type = OBJ_NAME_TYPE_MD_METH;
+  obj_name.name = name;
+
+  wrapped->callback(&obj_name, wrapped->arg);
+}
+
+void OBJ_NAME_do_all_sorted(int type,
+                            void (*callback)(const OBJ_NAME *, void *arg),
+                            void *arg) {
+  struct wrapped_callback wrapped;
+  wrapped.callback = callback;
+  wrapped.arg = arg;
+
+  if (type == OBJ_NAME_TYPE_CIPHER_METH) {
+    EVP_CIPHER_do_all_sorted(cipher_callback, &wrapped);
+  } else if (type == OBJ_NAME_TYPE_MD_METH) {
+    EVP_MD_do_all_sorted(md_callback, &wrapped);
+  } else {
+    assert(0);
+  }
+}
+
+void OBJ_NAME_do_all(int type, void (*callback)(const OBJ_NAME *, void *arg),
+                     void *arg) {
+  return OBJ_NAME_do_all_sorted(type, callback, arg);
+}
diff --git a/include/openssl/obj.h b/include/openssl/obj.h
index 32a4894..884cd18 100644
--- a/include/openssl/obj.h
+++ b/include/openssl/obj.h
@@ -189,6 +189,32 @@
                                           int pkey_nid);
 
 
+/* Deprecated functions. */
+
+typedef struct obj_name_st {
+  int type;
+  const char *name;
+} OBJ_NAME;
+
+#define OBJ_NAME_TYPE_MD_METH 1
+#define OBJ_NAME_TYPE_CIPHER_METH 2
+
+/* OBJ_NAME_do_all_sorted calls |callback| zero or more times, each time with
+ * the name of a different primitive. If |type| is |OBJ_NAME_TYPE_MD_METH| then
+ * the primitives will be hash functions, alternatively if |type| is
+ * |OBJ_NAME_TYPE_CIPHER_METH| then the primitives will be ciphers or cipher
+ * modes.
+ *
+ * This function is ill-specified and should never be used. */
+OPENSSL_EXPORT void OBJ_NAME_do_all_sorted(
+    int type, void (*callback)(const OBJ_NAME *, void *arg), void *arg);
+
+/* OBJ_NAME_do_all calls |OBJ_NAME_do_all_sorted|. */
+OPENSSL_EXPORT void OBJ_NAME_do_all(int type, void (*callback)(const OBJ_NAME *,
+                                                               void *arg),
+                                    void *arg);
+
+
 #if defined(__cplusplus)
 }  /* extern C */
 #endif