Allow sign extension in OSSL_PARAM_allocate_from_text()
authorRichard Levitte <levitte@openssl.org>
Mon, 22 Nov 2021 16:10:10 +0000 (17:10 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 24 Nov 2021 18:18:19 +0000 (19:18 +0100)
This is done for the data type OSSL_PARAM_INTEGER by checking if the
most significant bit is set, and adding 8 to the number of buffer bits
if that is the case.  Everything else is already in place.

Fixes #17103

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/17104)

crypto/params_from_text.c

index 43323c37075bbc142610c0c32f3226047248ba19..b681d8f56406837661c10cd16e7d9ba94dfe7e15 100644 (file)
@@ -61,7 +61,7 @@ static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
         }
 
         /*
-         * 2s complement negate, part 1
+         * 2's complement negate, part 1
          *
          * BN_bn2nativepad puts the absolute value of the number in the
          * buffer, i.e. if it's negative, we need to deal with it.  We do
@@ -76,6 +76,20 @@ static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
         }
 
         buf_bits = (size_t)BN_num_bits(*tmpbn);
+
+        /*
+         * Compensate for cases where the most significant bit in
+         * the resulting OSSL_PARAM buffer will be set after the
+         * BN_bn2nativepad() call, as the implied sign may not be
+         * correct after the second part of the 2's complement
+         * negation has been performed.
+         * We fix these cases by extending the buffer by one byte
+         * (8 bits), which will give some padding.  The second part
+         * of the 2's complement negation will do the rest.
+         */
+        if (p->data_type == OSSL_PARAM_INTEGER && buf_bits % 8 == 0)
+            buf_bits += 8;
+
         *buf_n = (buf_bits + 7) / 8;
 
         /*
@@ -83,9 +97,7 @@ static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
          * range checking if a size is specified.
          */
         if (p->data_size > 0) {
-            if (buf_bits > p->data_size * 8
-                || (p->data_type == OSSL_PARAM_INTEGER
-                    && buf_bits == p->data_size * 8)) {
+            if (buf_bits > p->data_size * 8) {
                 ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER);
                 /* Since this is a different error, we don't break */
                 return 0;
@@ -135,7 +147,7 @@ static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
             BN_bn2nativepad(tmpbn, buf, buf_n);
 
             /*
-             * 2s complement negate, part two.
+             * 2's complement negation, part two.
              *
              * Because we did the first part on the BIGNUM itself, we can just
              * invert all the bytes here and be done with it.