summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2016-02-22 15:31:38 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-03-30 20:38:12 -0700
commit19bfaa46e5d11f57d219962b6968f2518147a371 (patch)
tree999818c92e902ae0a17c0ea951a5842842d5e29b /chip
parent20f5efafc8c02ad1ada7dd1ca5256af9dfc439ab (diff)
downloadchrome-ec-19bfaa46e5d11f57d219962b6968f2518147a371.tar.gz
CR50: add support for RSA PKCS1-PSS padding
Add support for PSS padding as per RFC 3447. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 TEST=tests under tpm2 pass Change-Id: I14c58394f742daa5de4ec2fbeb7e7f14e54c9fcc Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/328778 Commit-Ready: Nagendra Modadugu <ngm@google.com> Tested-by: Nagendra Modadugu <ngm@google.com> Reviewed-by: Nagendra Modadugu <ngm@google.com>
Diffstat (limited to 'chip')
-rw-r--r--chip/g/dcrypto/dcrypto.h3
-rw-r--r--chip/g/dcrypto/rsa.c114
2 files changed, 115 insertions, 2 deletions
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
index c0422208ae..0856ec76c6 100644
--- a/chip/g/dcrypto/dcrypto.h
+++ b/chip/g/dcrypto/dcrypto.h
@@ -93,7 +93,8 @@ struct RSA {
enum padding_mode {
PADDING_MODE_PKCS1 = 0,
- PADDING_MODE_OAEP = 1
+ PADDING_MODE_OAEP = 1,
+ PADDING_MODE_PSS = 2
};
/* Calculate r = m ^ e mod N */
diff --git a/chip/g/dcrypto/rsa.c b/chip/g/dcrypto/rsa.c
index 5107773a30..02dbbf01f4 100644
--- a/chip/g/dcrypto/rsa.c
+++ b/chip/g/dcrypto/rsa.c
@@ -7,6 +7,7 @@
#include "internal.h"
#include "trng.h"
+#include "util.h"
#include <assert.h>
@@ -297,6 +298,107 @@ static int check_pkcs1_type1_pad(const uint8_t *msg, uint32_t msg_len,
return memcmp(msg, &padded[i], hash_size) == 0;
}
+/* sign */
+static int pkcs1_pss_pad(uint8_t *padded, uint32_t padded_len,
+ const uint8_t *in, uint32_t in_len,
+ enum hashing_mode hashing)
+{
+ const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA1_DIGEST_BYTES
+ : SHA256_DIGEST_BYTES;
+ const uint32_t salt_len = MIN(padded_len - hash_size - 2, hash_size);
+ uint32_t db_len;
+ uint32_t ps_len;
+ struct HASH_CTX ctx;
+
+ if (in_len != hash_size)
+ return 0;
+ if (padded_len < hash_size + 2)
+ return 0;
+ db_len = padded_len - hash_size - 1;
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+
+ /* Pilfer bits of output for temporary use. */
+ memset(padded, 0, 8);
+ DCRYPTO_HASH_update(&ctx, padded, 8);
+ DCRYPTO_HASH_update(&ctx, in, in_len);
+ /* Pilfer bits of output for temporary use. */
+ rand_bytes(padded, salt_len);
+ DCRYPTO_HASH_update(&ctx, padded, salt_len);
+
+ /* Output hash. */
+ memcpy(padded + db_len, DCRYPTO_HASH_final(&ctx), hash_size);
+
+ /* Prepare DB. */
+ ps_len = db_len - salt_len - 1;
+ memmove(padded + ps_len + 1, padded, salt_len);
+ memset(padded, 0, ps_len);
+ padded[ps_len] = 0x01;
+ MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing);
+
+ /* Clear most significant bit. */
+ padded[0] &= 0x7F;
+ /* Set trailing byte. */
+ padded[padded_len - 1] = 0xBC;
+ return 1;
+}
+
+/* verify */
+static int check_pkcs1_pss_pad(const uint8_t *in, uint32_t in_len,
+ uint8_t *padded, uint32_t padded_len,
+ enum hashing_mode hashing)
+{
+ const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA1_DIGEST_BYTES
+ : SHA256_DIGEST_BYTES;
+ const uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t db_len;
+ uint32_t max_ps_len;
+ uint32_t salt_len;
+ struct HASH_CTX ctx;
+ int bad = 0;
+ int i;
+
+ if (in_len != hash_size)
+ return 0;
+ if (padded_len < hash_size + 2)
+ return 0;
+ db_len = padded_len - hash_size - 1;
+
+ /* Top bit should be zero. */
+ bad |= padded[0] & 0x80;
+ /* Check trailing byte. */
+ bad |= padded[padded_len - 1] ^ 0xBC;
+
+ /* Recover DB. */
+ MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing);
+ /* Clear top bit. */
+ padded[0] &= 0x7F;
+ /* Verify padding2. */
+ max_ps_len = db_len - 1;
+ for (i = 0; i < max_ps_len; i++) {
+ if (padded[i] == 0x01)
+ break;
+ else
+ bad |= padded[i];
+ }
+ bad |= (padded[i] ^ 0x01);
+ /* Continue with zero-length salt if 0x01 was not found. */
+ salt_len = max_ps_len - i;
+
+ if (hashing == HASH_SHA1)
+ DCRYPTO_SHA1_init(&ctx, 0);
+ else
+ DCRYPTO_SHA256_init(&ctx, 0);
+ DCRYPTO_HASH_update(&ctx, zeros, sizeof(zeros));
+ DCRYPTO_HASH_update(&ctx, in, in_len);
+ DCRYPTO_HASH_update(&ctx, padded + db_len - salt_len, salt_len);
+ bad |= memcmp(padded + db_len, DCRYPTO_HASH_final(&ctx), hash_size);
+ return !bad;
+}
+
static int check_modulus_params(const struct BIGNUM *N, uint32_t *out_len)
{
if (bn_size(N) > RSA_MAX_BYTES)
@@ -421,13 +523,17 @@ int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
bn_init(&padded, padded_buf, bn_size(&rsa->N));
bn_init(&signature, out, bn_size(&rsa->N));
- /* TODO(ngm): add support for PSS. */
switch (padding) {
case PADDING_MODE_PKCS1:
if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded),
(const uint8_t *) in, in_len, hashing))
return 0;
break;
+ case PADDING_MODE_PSS:
+ if (!pkcs1_pss_pad((uint8_t *) padded.d, bn_size(&padded),
+ (const uint8_t *) in, in_len, hashing))
+ return 0;
+ break;
default:
return 0;
}
@@ -481,6 +587,12 @@ int DCRYPTO_rsa_verify(struct RSA *rsa, const uint8_t *digest,
bn_size(&padded), hashing))
ret = 0;
break;
+ case PADDING_MODE_PSS:
+ if (!check_pkcs1_pss_pad(
+ digest, digest_len, (uint8_t *) padded.d,
+ bn_size(&padded), hashing))
+ return 0;
+ break;
default:
/* Unsupported padding mode. */
ret = 0;