Stream: smart/health-cards
Topic: DER encoded signature
Stephen Whitney (May 21 2021 at 16:28):
We've leveraged AWS KMS to provision the EC keys for JWS signing. When we try to validate using the MS Smarthealth Card Validation SDK, this is the error we receive:
root@d79fd1cb1c55:/usr/src/app# node . --path /inputs/jws.smart-health-card --type jws
SMART Health Card Validation SDK v1.0.0-1
JWS-compact
│
├─ Warning
│ · Issuer key endpoint does not contain a 'access-control-allow-origin' header for Cross-Origin Resource Sharing (CORS)
│
├─ Error
│ · Schema: {"instancePath":"","schemaPath":"#/pattern","keyword":"pattern","params":{"pattern":"^[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+$"},"message":"must match pattern \"^[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+$\""}
│ · Can't parse JWS header as JSON.
│
│ · Signature appears to be in DER encoded form. Signature is expected to be 64-byte r||s concatenated form.
│ See https://tools.ietf.org/html/rfc7515#appendix-A.3 for expected ES256 signature form.
│
└─ JWS.payload
│
└─ FhirBundle
Validation completed
Has anyone come across these errors seen above?
Christian Paquin (May 21 2021 at 16:51):
Stephen Whitney said:
We've leveraged AWS KMS to provision the EC keys for JWS signing. Has anyone come across these errors seen above?
I get the same. The cited appendix 3 describe the proper encoding for the signature. How are you generating the JWS signature? (language, API, pseudocode?) We can help to see if that's the proper way to create it.
Stephen Whitney (May 21 2021 at 17:02):
We're using boto3 python SDK:
def _set_jws(self):
if environ not in [
"test",
]:
signature = self._sign_token(self.key_id, self.message)
verification = self._verify_signature(self.key_id, self.message, signature)
signed = (
self.message
+ b"."
+ base64.urlsafe_b64encode(signature).replace(b"=", b"")
)
return signed
else:
return self.message
def _sign_token(self, key_id, message):
signature = kms_client.sign(
KeyId=key_id,
Message=message,
MessageType="RAW",
SigningAlgorithm="ECDSA_SHA_256",
)
logger.log(msg=signature, level=cl.log_level)
return signature["Signature"]
Christian Paquin (May 21 2021 at 17:30):
Looks like the boto3 sign API returns a DER encoded signature:
When used with the ECDSA_SHA_256 , ECDSA_SHA_384 , or ECDSA_SHA_512 signing algorithms,
this value is a DER-encoded object as defined by ANS X9.62–2005 and RFC 3279 Section 2.2.3 .
This is the most commonly used signature format and is appropriate for most uses.
This will need to be converted to the raw r
and s
values expected in the JWS signature format. I'm not sure what is the best way to do this in python; I'll take a look...
Stephen Whitney (May 21 2021 at 18:03):
This post shows the code needed to unmarshall DER into raw R and S using Go. We're going to start a chat with AWS to see if they can help us in python.
Christian Paquin (May 21 2021 at 19:12):
Stephen Whitney said:
This post shows the code needed to unmarshall DER into raw R and S using Go. We're going to start a chat with AWS to see if they can help us in python.
Yes, you'd need to do the same in python (perhaps with this lib?) The ASN.1 encoding of an ECDSA sig is fairly simple (see section 2.2.3 of RFC 3279):
Ecdsa-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER }
Reece Adamson (May 21 2021 at 20:05):
We ran into something similar with our Ruby implementation. This GitHub PR (https://github.com/jpadilla/pyjwt/pull/158) in pyjwt
deals with this and has a python DER to Raw (and vice-versa) implementation thats pretty simple.
Stephen Whitney (May 21 2021 at 21:36):
thank you @Reece Adamson and @Christian Paquin . I'm so close now. I just need to figure out this last hurdle:
Signature is 69-bytes. Signature is expected to be 64-bytes
My guess is that it has to do with this:
https://github.com/jpadilla/pyjwt/blob/e0a288017d945f8dd7da2fa13d5defb85192e38a/jwt/utils.py#L60
Update: It's all good. Thank you again!
Last updated: Apr 12 2022 at 19:14 UTC