Make ranged for loops work with STACK_OF(T).

My original plan here was to make STACK_OF(T) expand to a template so
the inner type were extractable. Unfortunately, we cannot sanely make
STACK_OF(T) expand to a different type in C and C++ even across
compilation units because UBSan sometimes explodes. This is nuts, but so
it goes.

Instead, use StackTraits to extract the STACK_OF(T) parameters and
define an iterator type.

Bug: 189
Change-Id: I64f5173b34b723ec471f7a355ff46b04f161386a
Reviewed-on: https://boringssl-review.googlesource.com/18467
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/stack.h b/include/openssl/stack.h
index 8f15ea2..0e59d6a 100644
--- a/include/openssl/stack.h
+++ b/include/openssl/stack.h
@@ -222,21 +222,22 @@
 }
 }
 
-#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const) \
-  extern "C++" {                                      \
-  namespace bssl {                                    \
-  namespace internal {                                \
-  template <>                                         \
-  struct StackTraits<STACK_OF(name)> {                \
-    using Type = name;                                \
-    static constexpr bool kIsConst = is_const;        \
-  };                                                  \
-  }                                                   \
-  }                                                   \
+#define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) \
+  extern "C++" {                                            \
+  namespace bssl {                                          \
+  namespace internal {                                      \
+  template <>                                               \
+  struct StackTraits<STACK_OF(name)> {                      \
+    static constexpr bool kIsStack = true;                  \
+    using Type = type;                                      \
+    static constexpr bool kIsConst = is_const;              \
+  };                                                        \
+  }                                                         \
+  }                                                         \
   }
 
 #else
-#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const)
+#define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const)
 #endif
 
 /* Stack functions must be tagged unused to support file-local stack types.
@@ -350,15 +351,15 @@
 
 /* DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are
  * |type| *. */
-#define DEFINE_STACK_OF(type) \
+#define DEFINE_STACK_OF(type)                                \
   BORINGSSL_DEFINE_STACK_OF_IMPL(type, type *, const type *) \
-  BORINGSSL_DEFINE_STACK_TRAITS(type, false)
+  BORINGSSL_DEFINE_STACK_TRAITS(type, type, false)
 
 /* DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
  * are const |type| *. */
-#define DEFINE_CONST_STACK_OF(type) \
+#define DEFINE_CONST_STACK_OF(type)                                \
   BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \
-  BORINGSSL_DEFINE_STACK_TRAITS(type, true)
+  BORINGSSL_DEFINE_STACK_TRAITS(type, const type, true)
 
 /* DEFINE_SPECIAL_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
  * are |type|, where |type| must be a typedef for a pointer. */
@@ -407,10 +408,62 @@
   }
 };
 
+template <typename Stack>
+class StackIteratorImpl {
+ public:
+  using Type = typename StackTraits<Stack>::Type;
+  // Iterators must be default-constructable.
+  StackIteratorImpl() : sk_(nullptr), idx_(0) {}
+  StackIteratorImpl(const Stack *sk, size_t idx) : sk_(sk), idx_(idx) {}
+
+  bool operator==(StackIteratorImpl other) const {
+    return sk_ == other.sk_ && idx_ == other.idx_;
+  }
+  bool operator!=(StackIteratorImpl other) const {
+    return !(*this == other);
+  }
+
+  Type *operator*() const {
+    return reinterpret_cast<Type *>(
+        sk_value(reinterpret_cast<const _STACK *>(sk_), idx_));
+  }
+
+  StackIteratorImpl &operator++(/* prefix */) {
+    idx_++;
+    return *this;
+  }
+
+  StackIteratorImpl operator++(int /* postfix */) {
+    StackIteratorImpl copy(*this);
+    ++(*this);
+    return copy;
+  }
+
+ private:
+  const Stack *sk_;
+  size_t idx_;
+};
+
+template <typename Stack>
+using StackIterator = typename std::enable_if<StackTraits<Stack>::kIsStack,
+                                              StackIteratorImpl<Stack>>::type;
+
 }  // namespace internal
 
 }  // namespace bssl
 
+// Define begin() and end() for stack types so C++ range for loops work.
+template <typename Stack>
+static inline bssl::internal::StackIterator<Stack> begin(const Stack *sk) {
+  return bssl::internal::StackIterator<Stack>(sk, 0);
+}
+
+template <typename Stack>
+static inline bssl::internal::StackIterator<Stack> end(const Stack *sk) {
+  return bssl::internal::StackIterator<Stack>(
+      sk, sk_num(reinterpret_cast<const _STACK *>(sk)));
+}
+
 }  // extern C++
 #endif
 
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index 0fcf48d..4337ec0 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -721,9 +721,7 @@
     return CBB_flush(cbb);
   }
 
-  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
-    const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);
-
+  for (const CRYPTO_BUFFER *name : names) {
     if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
         !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
                        CRYPTO_BUFFER_len(name))) {