簡體   English   中英

使用 mbedtls 生成的 ECDSA 簽名無法在 JOSE 中驗證(而代碼使用 RSA 密鑰)

[英]ECDSA signature generated with mbedtls not verifiable in JOSE (while code worked with RSA key)

我有一個在 ESP32 開發板上運行的小應用程序(我將 Arduino IDE 與隨附的mbedtls一起使用)發出並驗證 JWT 令牌。 我起初成功地使用了 RSA 簽名,但現在想使用 go 來獲得更短的簽名,因此嘗試使用 ECDSA。 應用程序本身也可以發布令牌並驗證它們,但是如果我嘗試在我的應用程序外部驗證令牌 - 例如使用JOSE調試器- 我會遇到驗證失敗並且我無法完全理解為什么會發生這種情況。

這是一個示例令牌(此令牌實際上不包含信息):

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzI0MTMxNjgsImV4cCI6MTY3MjQxNjc2OH0.MEUCIAjwEDXI424qjrAkSzZ_ydcVLOSAvfQ8YVddYvzDzMvQAiEAkVy4d-hZ01KpcMNKhPHk8E_SDYiB4JKwhm-Kc-Z81rI

這是對應的公鑰(除了這里提出問題的目的外,沒有在任何地方使用這個密鑰):

-----開始公鑰----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUGnNIOhPhZZSOg4A4BqAFtGO13W4BGDQpQ0ieTvLU9/CXrY7W77o7pNx7tvugeIoYJxS0NjmxvT4TMpo4Z--KEY-P-7A== --LIC

據我了解,可以使用 ECDSA 發行和驗證 JWT 個令牌。 所謂的“ES256”方法應該結合使用 prime256v1和 SHA256,因此我使用以下命令生成了我的密鑰材料:

openssl ecparam -name prime256v1 -genkey -noout -out ecc-private.pem
openssl ec -in ecc-private.pem -pubout -out ecc-public.pem

對於簽名部分,私鑰按如下方式加載,其中 ecc_priv 是一個包含密鑰的 PEM 表示的字符串:

//get the key
byte *keybuffer = (byte*)malloc((ecc_priv.length()+1)*sizeof(byte));
ecc_priv.getBytes(keybuffer, ecc_priv.length() + 1);
mbedtls_pk_context pk_context;
mbedtls_pk_init(&pk_context);
int rc = mbedtls_pk_parse_key(&pk_context, keybuffer, ecc_priv.length() + 1, NULL, 0);
if (rc != 0){
 printf("Failed to mbedtls_pk_parse_key: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
 return -1;
}
free(keybuffer);

因為這對我來說適用於 RSA 密鑰,所以我只是替換了密鑰並保留了所有其他代碼來簽署實際消息。 據我了解,這應該可以通過 mbedtls_pk 方法實現:

//mbedtls context
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);

const char* pers="some entropy";
                
mbedtls_ctr_drbg_seed(
  &ctr_drbg,
  mbedtls_entropy_func,
  &entropy,
  (const unsigned char*)pers,
  strlen(pers));
//get the header and payload bytes    
byte *headerAndPayloadbytes = (byte*)malloc((headerAndPayload.length()+1)*sizeof(byte));
headerAndPayload.getBytes(headerAndPayloadbytes, headerAndPayload.length() + 1);
//prepare digest
uint8_t digest[32];
rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), headerAndPayloadbytes, headerAndPayload.length(), digest);
if (rc != 0) {
  printf("Failed to mbedtls_md: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
  return -1;        
}
free(headerAndPayloadbytes);
//prepare output
byte *oBuf = (byte*)malloc(5000*sizeof(byte));
size_t retSize;
//sign digest
rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), oBuf, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg);
if (rc != 0) {
  printf("Failed to mbedtls_pk_sign: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
  return -1;        
}
//encode signature to base64
unsigned int osize = encode_base64_length(retSize);
byte *output = (byte*)malloc((osize+1)*sizeof(byte));
encode_base64(oBuf, retSize, output);
String sig = String((char*)output);
free(output);
//base64 URL specific
sig.replace('+','-');
sig.replace('/','_');
sig.replace("=","");
String completejwt = headerAndPayload + "." + sig;
//free resources
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
mbedtls_pk_free(&pk_context);
free(oBuf);

我的期望是我可以簡單地將 RSA 密鑰替換為 ECDSA (prime256v1) 密鑰並保持其他一切不變,但生成的令牌無法在我的應用程序之外驗證。 我想再次強調,在我的應用程序中,我絕對可以驗證令牌,並且即使在我的應用程序之外,代碼也可以使用 RSA 密鑰完美地工作。 這里一定有我遺漏的東西,我確定。 非常感謝任何幫助或研究方向。

編輯:這是一個最小的可編譯示例(Arduino sketch)

您的 ECDSA 簽名是 DER 編碼的 ASN.1 結構,而不是簡單的 r || IEEE-P1363 提出的 s 級聯,這是 JOSE 規范的要求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM