Skip to content

Commit

Permalink
crypto/caam: bugfix: ECDSA r/s alignment
Browse files Browse the repository at this point in the history
The previous assumption was that the CAAM did not like leading zero
bytes on the R/S integers.

The R/S values are DER encoded 2 complement integers that might have a
leading zero byte if the MSB in the first byte is 1. That bit is the
sign bit and ECDSA integers are always positive.

The CAAM expects the R/S integers to have the following lengths:

 - 32 bytes for secp256r1
 - 48 bytes for secp384r1
 - 66 bytes for secp521r1

This means that sometimes the R/S values can be larger than what the
CAAM expects and in that case the zero byte must be stripped.

If however the encoded integer is shorter it must be prepended with zero
bytes to match the above table.
  • Loading branch information
Jonas Blixt authored and jonasblixt committed Jul 4, 2023
1 parent 7b7609b commit c61b074
Showing 1 changed file with 49 additions and 7 deletions.
56 changes: 49 additions & 7 deletions src/drivers/crypto/caam/imx_caam.c
Expand Up @@ -47,6 +47,7 @@
#include <pb/mmio.h>
#include <arch/arch.h>
#include <pb/pb.h>
#include <pb/utils_def.h>
#include <bpak/keystore.h>
#include <pb/crypto.h>
#include <pb/der_helpers.h>
Expand Down Expand Up @@ -183,6 +184,45 @@ static int caam_shedule_job_sync(void)
return caam_wait_for_job();
}

static int caam_der_ecsig_to_rs(const uint8_t *sig, size_t rs_length, uint8_t *r, uint8_t *s)
{
size_t sz;
int rc;
const uint8_t *p = sig;

if (*p++ != 0x30) {
return -PB_ERR_ASN1;
}

rc = asn1_size(&p, &sz);

if (rc != 0)
return rc;

if (*p++ != 0x02)
return -PB_ERR_ASN1;

rc = asn1_size(&p, &sz);

if (rc != 0)
return rc;

memcpy(&r[MAX((int) (rs_length - sz), 0)], &p[MAX((int) (sz - rs_length), 0)], sz);
p += sz;

if (*p++ != 0x02)
return -PB_ERR_ASN1;

rc = asn1_size(&p, &sz);

if (rc != 0)
return rc;

memcpy(&s[MAX((int) (rs_length - sz), 0)], &p[MAX((int) (sz - rs_length), 0)], sz);

return PB_OK;
}

static int caam_ecda_verify(const uint8_t *der_signature, size_t sig_length,
const uint8_t *der_key, size_t key_length,
hash_t md_alg, uint8_t *md, size_t md_length,
Expand All @@ -191,6 +231,7 @@ static int caam_ecda_verify(const uint8_t *der_signature, size_t sig_length,
int rc;
int dc = 0;
int caam_sig_type = 0;
size_t rs_length = 0;
dsa_t key_kind;

*verified = false;
Expand All @@ -205,29 +246,30 @@ static int caam_ecda_verify(const uint8_t *der_signature, size_t sig_length,
if (rc != PB_OK)
return rc;

rc = der_ecsig_to_rs(der_signature,
caam.ecdsa_r, caam.ecdsa_s, CAAM_SIG_MAX_LENGTH/2,
true);

if (rc != PB_OK)
return rc;

memset(caam.ecdsa_tmp_buf, 0, sizeof(caam.ecdsa_tmp_buf));

switch (key_kind) {
case DSA_EC_SECP256r1:
caam_sig_type = 2;
rs_length = 32;
break;
case DSA_EC_SECP384r1:
caam_sig_type = 3;
rs_length = 48;
break;
case DSA_EC_SECP521r1:
caam_sig_type = 4;
rs_length = 66;
break;
default:
return -PB_ERR_NOT_SUPPORTED;
};

rc = caam_der_ecsig_to_rs(der_signature, rs_length, caam.ecdsa_r, caam.ecdsa_s);

if (rc != PB_OK)
return rc;

arch_clean_cache_range((uintptr_t) caam.ecdsa_tmp_buf,
sizeof(caam.ecdsa_tmp_buf));
arch_clean_cache_range((uintptr_t) caam.ecdsa_key, sizeof(caam.ecdsa_key));
Expand Down

0 comments on commit c61b074

Please sign in to comment.