Ensure EC private keys retain leading zeros
authorDouglas E Engert <deengert@gmail.com>
Wed, 25 Mar 2015 23:52:28 +0000 (23:52 +0000)
committerMatt Caswell <matt@openssl.org>
Tue, 31 Mar 2015 15:38:20 +0000 (16:38 +0100)
RFC5915 requires the use of the I2OSP primitive as defined in RFC3447
for storing an EC Private Key. This converts the private key into an
OCTETSTRING and retains any leading zeros. This commit ensures that those
leading zeros are present if required.

Reviewed-by: Andy Polyakov <appro@openssl.org>
(cherry picked from commit 30cd4ff294252c4b6a4b69cbef6a5b4117705d22)

Conflicts:
crypto/ec/ec_asn1.c

crypto/ec/ec_asn1.c

index b4b0e9f3b82a2bde381978071d385eb4bd9bc4f0..4ad8494981bfc4c8e81926f14b753fc2729fc713 100644 (file)
@@ -1114,7 +1114,7 @@ int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
 {
     int ret = 0, ok = 0;
     unsigned char *buffer = NULL;
-    size_t buf_len = 0, tmp_len;
+    size_t buf_len = 0, tmp_len, bn_len;
     EC_PRIVATEKEY *priv_key = NULL;
 
     if (a == NULL || a->group == NULL || a->priv_key == NULL ||
@@ -1130,18 +1130,32 @@ int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out)
 
     priv_key->version = a->version;
 
-    buf_len = (size_t)BN_num_bytes(a->priv_key);
+    bn_len = (size_t)BN_num_bytes(a->priv_key);
+
+    /* Octetstring may need leading zeros if BN is to short */
+
+    buf_len = (EC_GROUP_get_degree(a->group) + 7) / 8;
+
+    if (bn_len > buf_len) {
+        ECerr(EC_F_I2D_ECPRIVATEKEY, EC_R_BUFFER_TOO_SMALL);
+        goto err;
+    }
+
     buffer = OPENSSL_malloc(buf_len);
     if (buffer == NULL) {
         ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
-    if (!BN_bn2bin(a->priv_key, buffer)) {
+    if (!BN_bn2bin(a->priv_key, buffer + buf_len - bn_len)) {
         ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_BN_LIB);
         goto err;
     }
 
+    if (buf_len - bn_len > 0) {
+        memset(buffer, 0, buf_len - bn_len);
+    }
+
     if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) {
         ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB);
         goto err;