base64: fix underflow in EVP_EncodeBlock.

When I switched the base64 code to use size_t, I missed that one of the
loops was counting down, not up, and depended on the loop variable going
negative.

Additionally this change fixes a bug in NETSCAPE_SPKI_b64_encode where
the size of the result buffer was incorrectly calculated and a possible
memory leak.

Change-Id: Ibdf644244291274f50b314f3bb13a61b46858ca1
Reviewed-on: https://boringssl-review.googlesource.com/1220
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/base64/base64.c b/crypto/base64/base64.c
index 94c3055..58e6151 100644
--- a/crypto/base64/base64.c
+++ b/crypto/base64/base64.c
@@ -121,7 +121,7 @@
 
   assert(ctx->length <= sizeof(ctx->enc_data));
 
-  if ((ctx->num + in_len) < ctx->length) {
+  if (ctx->num + in_len < ctx->length) {
     memcpy(&ctx->enc_data[ctx->num], in, in_len);
     ctx->num += in_len;
     return;
@@ -167,26 +167,28 @@
 }
 
 size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
-  unsigned long l;
-  size_t i, ret = 0;
+  uint32_t l;
+  size_t remaining = src_len, ret = 0;
 
-  for (i = src_len; i > 0; i -= 3) {
-    if (i >= 3) {
-      l = (((unsigned long)src[0]) << 16L) | (((unsigned long)src[1]) << 8L) | src[2];
+  while (remaining) {
+    if (remaining >= 3) {
+      l = (((uint32_t)src[0]) << 16L) | (((uint32_t)src[1]) << 8L) | src[2];
       *(dst++) = conv_bin2ascii(l >> 18L);
       *(dst++) = conv_bin2ascii(l >> 12L);
       *(dst++) = conv_bin2ascii(l >> 6L);
       *(dst++) = conv_bin2ascii(l);
+      remaining -= 3;
     } else {
-      l = ((unsigned long)src[0]) << 16L;
-      if (i == 2) {
-        l |= ((unsigned long)src[1] << 8L);
+      l = ((uint32_t)src[0]) << 16L;
+      if (remaining == 2) {
+        l |= ((uint32_t)src[1] << 8L);
       }
 
       *(dst++) = conv_bin2ascii(l >> 18L);
       *(dst++) = conv_bin2ascii(l >> 12L);
-      *(dst++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L);
+      *(dst++) = (remaining == 1) ? '=' : conv_bin2ascii(l >> 6L);
       *(dst++) = '=';
+      remaining = 0;
     }
     ret += 4;
     src += 3;
@@ -357,7 +359,7 @@
 
 size_t EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
   int a, b, c, d;
-  unsigned long l;
+  uint32_t l;
   size_t i, ret = 0;
 
   /* trim white space from the start of the line. */
@@ -384,8 +386,8 @@
     if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
       return -1;
     }
-    l = ((((unsigned long)a) << 18L) | (((unsigned long)b) << 12L) |
-         (((unsigned long)c) << 6L) | (((unsigned long)d)));
+    l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
+         (((uint32_t)c) << 6L) | (((uint32_t)d)));
     *(dst++) = (uint8_t)(l >> 16L) & 0xff;
     *(dst++) = (uint8_t)(l >> 8L) & 0xff;
     *(dst++) = (uint8_t)(l) & 0xff;
diff --git a/crypto/x509/x509spki.c b/crypto/x509/x509spki.c
index ffadcb4..243a7d2 100644
--- a/crypto/x509/x509spki.c
+++ b/crypto/x509/x509spki.c
@@ -105,8 +105,13 @@
 	int der_len;
 	der_len = i2d_NETSCAPE_SPKI(spki, NULL);
 	der_spki = OPENSSL_malloc(der_len);
-	b64_str = OPENSSL_malloc(der_len * 2);
-	if(!der_spki || !b64_str) {
+	if (der_spki == NULL) {
+		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_MALLOC_FAILURE);
+		return NULL;
+	}
+	b64_str = OPENSSL_malloc((der_len + 2) / 3 * 4 + 1);
+	if (b64_str == NULL) {
+		OPENSSL_free(der_spki);
 		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}