[tor-commits] [tor/master] Unify functions for reading/writing PEM keys, to avoid duplication.

nickm at torproject.org nickm at torproject.org
Wed Sep 5 00:47:14 UTC 2018


commit 3b5d6ef15bec26c3bda22057ba09e1301613ee71
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Aug 29 16:43:54 2018 -0400

    Unify functions for reading/writing PEM keys, to avoid duplication.
---
 src/lib/crypt_ops/crypto_rsa.c | 145 ++++++++++++++++++++---------------------
 1 file changed, 71 insertions(+), 74 deletions(-)

diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c
index 31497e650..6a9e2948f 100644
--- a/src/lib/crypt_ops/crypto_rsa.c
+++ b/src/lib/crypt_ops/crypto_rsa.c
@@ -398,29 +398,43 @@ crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out)
 static const char RSA_PUBLIC_TAG[] = "RSA PUBLIC KEY";
 static const char RSA_PRIVATE_TAG[] = "RSA PRIVATE KEY";
 
-/** PEM-encode the public key portion of <b>env</b> and write it to a
- * newly allocated string.  On success, set *<b>dest</b> to the new
- * string, *<b>len</b> to the string's length, and return 0.  On
- * failure, return -1.
+/* These are overestimates for how many extra bytes we might need to encode
+ * a key in DER */
+#define PRIVATE_ASN_MAX_OVERHEAD_FACTOR 16
+#define PUBLIC_ASN_MAX_OVERHEAD_FACTOR 3
+
+/** Helper: PEM-encode <b>env</b> and write it to a newly allocated string.
+ * If <b>private_key</b>, write the private part of <b>env</b>; otherwise
+ * write only the public portion. On success, set *<b>dest</b> to the new
+ * string, *<b>len</b> to the string's length, and return 0.  On failure,
+ * return -1.
  */
-int
-crypto_pk_write_public_key_to_string(crypto_pk_t *env,
-                                     char **dest, size_t *len)
+static int
+crypto_pk_write_to_string_generic(crypto_pk_t *env,
+                                  char **dest, size_t *len,
+                                  bool private_key)
 {
-  size_t buflen = crypto_pk_keysize(env) * 3;
+  const int factor =
+    private_key ? PRIVATE_ASN_MAX_OVERHEAD_FACTOR
+                : PUBLIC_ASN_MAX_OVERHEAD_FACTOR;
+  size_t buflen = crypto_pk_keysize(env) * factor;
+  const char *tag =
+    private_key ? RSA_PRIVATE_TAG : RSA_PUBLIC_TAG;
   char *buf = tor_malloc(buflen);
   char *result = NULL;
   size_t resultlen = 0;
   int rv = -1;
 
-  int n = crypto_pk_asn1_encode(env, buf, buflen);
+  int n = private_key
+    ? crypto_pk_asn1_encode_private(env, buf, buflen)
+    : crypto_pk_asn1_encode(env, buf, buflen);
   if (n < 0)
     goto done;
 
-  resultlen = pem_encoded_size(n, RSA_PUBLIC_TAG);
+  resultlen = pem_encoded_size(n, tag);
   result = tor_malloc(resultlen);
   if (pem_encode(result, resultlen,
-                 (const unsigned char *)buf, n, RSA_PUBLIC_TAG) < 0) {
+                 (const unsigned char *)buf, n, tag) < 0) {
     goto done;
   }
 
@@ -438,6 +452,18 @@ crypto_pk_write_public_key_to_string(crypto_pk_t *env,
   return rv;
 }
 
+/** PEM-encode the public key portion of <b>env</b> and write it to a
+ * newly allocated string.  On success, set *<b>dest</b> to the new
+ * string, *<b>len</b> to the string's length, and return 0.  On
+ * failure, return -1.
+ */
+int
+crypto_pk_write_public_key_to_string(crypto_pk_t *env,
+                                     char **dest, size_t *len)
+{
+  return crypto_pk_write_to_string_generic(env, dest, len, false);
+}
+
 /** PEM-encode the private key portion of <b>env</b> and write it to a
  * newly allocated string.  On success, set *<b>dest</b> to the new
  * string, *<b>len</b> to the string's length, and return 0.  On
@@ -447,59 +473,42 @@ int
 crypto_pk_write_private_key_to_string(crypto_pk_t *env,
                                           char **dest, size_t *len)
 {
-  size_t buflen = crypto_pk_keysize(env) * 16;
-  char *buf = tor_malloc(buflen);
-  char *result = NULL;
-  size_t resultlen = 0;
-  int rv = -1;
-
-  int n = crypto_pk_asn1_encode_private(env, buf, buflen);
-  if (n < 0)
-    goto done;
-
-  resultlen = pem_encoded_size(n, RSA_PRIVATE_TAG);
-  result = tor_malloc(resultlen);
-  if (pem_encode(result, resultlen,
-                 (const unsigned char *)buf, n, RSA_PRIVATE_TAG) < 0)
-    goto done;
-
-  *dest = result;
-  *len = resultlen;
-  rv = 0;
- done:
-  if (rv < 0 && result) {
-    memwipe(result, 0, resultlen);
-    tor_free(result);
-  }
-  memwipe(buf, 0, buflen);
-  tor_free(buf);
-  return rv;
+  return crypto_pk_write_to_string_generic(env, dest, len, true);
 }
 
-/** Read a PEM-encoded public key from the first <b>len</b> characters of
- * <b>src</b>, and store the result in <b>env</b>.  Return 0 on success, -1 on
- * failure.
+/**
+ * Helper. Read a PEM-encoded RSA from the first <b>len</b> characters of
+ * <b>src</b>, and store the result in <b>env</b>.  If <b>private_key</b>,
+ * expect a private key; otherwise expect a public key. Return 0 on success,
+ * -1 on failure.  If len is -1, the string is nul-terminated.
  */
-int
-crypto_pk_read_public_key_from_string(crypto_pk_t *env,
-                                      const char *src, size_t len)
+static int
+crypto_pk_read_from_string_generic(crypto_pk_t *env, const char *src,
+                                   size_t len, bool private_key)
 {
-  if (len == (size_t)-1)
+  if (len == (size_t)-1) // "-1" indicates "use the length of the string."
     len = strlen(src);
 
+  const char *tag =
+    private_key ? RSA_PRIVATE_TAG : RSA_PUBLIC_TAG;
   size_t buflen = len;
   uint8_t *buf = tor_malloc(buflen);
   int rv = -1;
 
-  int n = pem_decode(buf, buflen, src, len, RSA_PUBLIC_TAG);
+  int n = pem_decode(buf, buflen, src, len, tag);
   if (n < 0)
     goto done;
 
-  crypto_pk_t *pk = crypto_pk_asn1_decode((const char*)buf, n);
+  crypto_pk_t *pk = private_key
+    ? crypto_pk_asn1_decode_private((const char*)buf, n)
+    : crypto_pk_asn1_decode((const char*)buf, n);
   if (! pk)
     goto done;
 
-  crypto_pk_assign_public(env, pk);
+  if (private_key)
+    crypto_pk_assign_private(env, pk);
+  else
+    crypto_pk_assign_public(env, pk);
   crypto_pk_free(pk);
   rv = 0;
 
@@ -509,38 +518,26 @@ crypto_pk_read_public_key_from_string(crypto_pk_t *env,
   return rv;
 }
 
-/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b>
+/** Read a PEM-encoded public key from the first <b>len</b> characters of
+ * <b>src</b>, and store the result in <b>env</b>.  Return 0 on success, -1 on
+ * failure.  If len is -1, the string is nul-terminated.
+ */
+int
+crypto_pk_read_public_key_from_string(crypto_pk_t *env,
+                                      const char *src, size_t len)
+{
+  return crypto_pk_read_from_string_generic(env, src, len, false);
+}
+
+/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>src</b>
  * into <b>env</b>.  Return 0 on success, -1 on failure.  If len is -1,
  * the string is nul-terminated.
  */
 int
 crypto_pk_read_private_key_from_string(crypto_pk_t *env,
-                                       const char *s, ssize_t len)
+                                       const char *src, ssize_t len)
 {
-  if (len == -1)
-    len = strlen(s);
-
-  size_t buflen = len;
-  uint8_t *buf = tor_malloc(buflen);
-  int rv = -1;
-
-  int n = pem_decode(buf, buflen, s, len, RSA_PRIVATE_TAG);
-  if (n < 0) {
-    goto done;
-  }
-
-  crypto_pk_t *pk = crypto_pk_asn1_decode_private((const char *)buf, n);
-  if (! pk)
-    goto done;
-
-  crypto_pk_assign_private(env, pk);
-  crypto_pk_free(pk);
-  rv = 0;
-
- done:
-  memwipe(buf, 0, buflen);
-  tor_free(buf);
-  return rv;
+  return crypto_pk_read_from_string_generic(env, src, len, true);
 }
 
 /** Read a PEM-encoded private key from the file named by





More information about the tor-commits mailing list