FHIR Chat · DER encoded signature · smart/health-cards

Stream: smart/health-cards

Topic: DER encoded signature


view this post on Zulip 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?

view this post on Zulip 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.

view this post on Zulip 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"]

view this post on Zulip 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...

view this post on Zulip 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.

https://aws.amazon.com/blogs/security/how-to-verify-aws-kms-signatures-in-decoupled-architectures-at-scale/

view this post on Zulip 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.

https://aws.amazon.com/blogs/security/how-to-verify-aws-kms-signatures-in-decoupled-architectures-at-scale/

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  }

view this post on Zulip 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.

view this post on Zulip 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