mozilla / openbadges-validator

Tools for validating openbadges assertions
Mozilla Public License 2.0
14 stars 13 forks source link

Elliptic Curve signed assertions are not following the JWS draft standard #30

Open jcea opened 9 years ago

jcea commented 9 years ago

Sent to "openbadges@googlegroups.com" 27th november:

""" I have spend three days debugging this.

I am generating signed openbadges according to https://github.com/openbadges/openbadges-specification/blob/master/Assertion/latest.md#signed-badges. I am using Elliptic Curves (standard p256) and creating JWS along the description in http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html#ES256Example.

In that documentation the signature serialization is described as:

""" The ECDSA private part d is then passed to an ECDSA signing function, which also takes the curve type, P-256, the hash type, SHA-256, and the JWS Signing Input as inputs. The result of the digital signature is the EC point (R, S), where R and S are unsigned integers. [...] The JWS Signature is the value R || S. """

Note the last line: the signature is the concatenation of the RAW "R||S".

Checking my signatures with http://validator.openbadges.org/ failed.

After hours/days of checking my code and doing EC signing by hand :-( I realized that the validator REQUIRES the JWS signature to use DER encoding. That makes sense, actually, but it is NOT what the JWS draft mandates.

I would like to know which one is correct: the JWS draft or the Openbadges Validator.

Please, reply.

Thanks!. """

I reproduce this trivially using Elliptic Curves crypto (P256).

Example of an signed assertion passing the test at http://validator.openbadges.org/ , using DER encoding for the signature, intead of the "standard required" raw R+S values:

"""eyJhbGciOiAiRVMyNTYifQ.eyJiYWRnZSI6ICJodHRwczovL29wZW5iYWRnZXMubHVpc2dmLmVzL2lzc3Vlci9iYWRnZS1sdWlzZ2YuanNvbiIsICJyZWNpcGllbnQiOiB7Imhhc2hlZCI6ICJ0cnVlIiwgImlkZW50aXR5IjogInNoYTI1NiRlMWNlNDc4NDUyOGM3ZGY5YmI2YTA0ZmRmZjRjZjU1OTZiOWM1MjNhN2U0MGE2MzVmYjZkYWJhYjhjZDIzYjEwIiwgInR5cGUiOiAiZW1haWwifSwgImltYWdlIjogImh0dHBzOi8vb3BlbmJhZGdlcy5sdWlzZ2YuZXMvaXNzdWVyL2JhZGdlcy9pbWFnZS5wbmciLCAidWlkIjogIjQ3M2NmNmRiYTJlOGYzNjRkM2UxNjc1YmRiMGY0NDg5MGM4ZjJjMzYiLCAiaXNzdWVkT24iOiAxNDE2OTEyNjQ1LCAidmVyaWZ5IjogeyJ1cmwiOiAiaHR0cHM6Ly9vcGVuYmFkZ2VzLmx1aXNnZi5lcy9pc3N1ZXIvcHVia2V5cy92ZXJpZnkucGVtIiwgInR5cGUiOiAic2lnbmVkIn19.MEQCIC69pvqBaN_2W03DXalJ0XFhb8zm-j9sfjmjy-ZbuaKQAiAz43dgcwmvYBek00_ShOFs4qSRAX-MRFmMDrFqNE3nLQ""".

jcea commented 9 years ago

I just uploaded a test ECC key in "https://openbadges.es.python.org/python-madrid/verify_ecc_key_openbadges-validator_issue_30.pem". It will live there until we solve this issue.

This assertion works fine in http://validator.openbadges.org/:

eyJhbGciOiAiRVMyNTYifQ.eyJpc3N1ZWRPbiI6IDE0MTg5NDI0NjgsICJ1aWQiOiAiZGFhNTNlNWI1NGVmZmJlNWQ0OWNmNWEzMzU1YjQxYWRkMDc3MTdjNiIsICJpbWFnZSI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3BvbmVudGUyMDE0LnN2ZyIsICJ2ZXJpZnkiOiB7InR5cGUiOiAic2lnbmVkIiwgInVybCI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3ZlcmlmeV9lY2Nfa2V5X29wZW5iYWRnZXMtdmFsaWRhdG9yX2lzc3VlXzMwLnBlbSJ9LCAiYmFkZ2UiOiAiaHR0cHM6Ly9vcGVuYmFkZ2VzLmVzLnB5dGhvbi5vcmcvcHl0aG9uLW1hZHJpZC9wb25lbnRlMjAxNC5qc29uIiwgInJlY2lwaWVudCI6IHsic2FsdCI6ICJkOTQzNTZiYTdmYTdiZWU2MzViOTNmZGYyYzQ5ZTE3OSIsICJoYXNoZWQiOiAidHJ1ZSIsICJ0eXBlIjogImVtYWlsIiwgImlkZW50aXR5IjogInNoYTI1NiRhMDYwMDA0YTRlMzlkODBlOTQ2ODVhOWUyNzM1OWEzOGVkMjZiNjM4NTkzMDdlYWNiNTZiYTFjYzlhYjY4MGZjIn19.MEYCIQD2OZrSVoKUftIuVS_U6x4KbAGyiL11WbwcnCM-67j9zAIhAMFiU_y9HjC5dawbEEyoMwLjBjrxH0vmmNU5_f-jfb38

This assertion uses DER encoding for the signature. JWS draft MANDATES raw "R" and "S" values, as described previously.

A (teorically) correct JWS assertion would be this. We can't verify it is correct, though:

eyJhbGciOiAiRVMyNTYifQ.eyJpc3N1ZWRPbiI6IDE0MTg5NDI0NjgsICJ1aWQiOiAiZGFhNTNlNWI1NGVmZmJlNWQ0OWNmNWEzMzU1YjQxYWRkMDc3MTdjNiIsICJpbWFnZSI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3BvbmVudGUyMDE0LnN2ZyIsICJ2ZXJpZnkiOiB7InR5cGUiOiAic2lnbmVkIiwgInVybCI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3ZlcmlmeV9lY2Nfa2V5X29wZW5iYWRnZXMtdmFsaWRhdG9yX2lzc3VlXzMwLnBlbSJ9LCAiYmFkZ2UiOiAiaHR0cHM6Ly9vcGVuYmFkZ2VzLmVzLnB5dGhvbi5vcmcvcHl0aG9uLW1hZHJpZC9wb25lbnRlMjAxNC5qc29uIiwgInJlY2lwaWVudCI6IHsic2FsdCI6ICJkOTQzNTZiYTdmYTdiZWU2MzViOTNmZGYyYzQ5ZTE3OSIsICJoYXNoZWQiOiAidHJ1ZSIsICJ0eXBlIjogImVtYWlsIiwgImlkZW50aXR5IjogInNoYTI1NiRhMDYwMDA0YTRlMzlkODBlOTQ2ODVhOWUyNzM1OWEzOGVkMjZiNjM4NTkzMDdlYWNiNTZiYTFjYzlhYjY4MGZjIn19.MEYCIQD2OZrSVoKUftIuVS_U6x4KbAGyiL11WbwcnCM-67j9zA

I just verified that Mozilla Backpack has this very same bug.

ottonomy commented 9 years ago

For quicker analysis, here are the decoded components of the two example signed assertions @jcea provided in the previous comment:

Here's the Header and claims for both of the badge objects, decoded:

{
    "alg": "ES256"
}
.
{
    "issuedOn": 1418942468, 
    "uid": "daa53e5b54effbe5d49cf5a3355b41add07717c6", 
    "verify": {
        "url": "https://openbadges.es.python.org/python-madrid/verify_ecc_key_openbadges-validator_issue_30.pem", 
        "type": "signed"
    }, 
    "image": "https://openbadges.es.python.org/python-madrid/ponente2014.svg", 
    "badge": "https://openbadges.es.python.org/python-madrid/ponente2014.json", 
    "recipient": {
        "type": "email", 
        "salt": "d94356ba7fa7bee635b93fdf2c49e179", 
        "hashed": "true", 
        "identity": "sha256$a060004a4e39d80e94685a9e27359a38ed26b63859307eacb56ba1cc9ab680fc"
    }
}

And here are the two signature values isolated. The first is the one that the validator can handle just fine, the second is the one @jcea says should be considered correct according to the JWS spec.

MEYCIQD2OZrSVoKUftIuVS_U6x4KbAGyiL11WbwcnCM-67j9zAIhAMFiU_y9HjC5dawbEEyoMwLjBjrxH0vmmNU5_f-jfb38

MEYCIQD2OZrSVoKUftIuVS_U6x4KbAGyiL11WbwcnCM-67j9zA

Here's a link to this section of the JWS draft: https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-06#appendix-A.3

I admit that I still don't understand what is happening here. The example from the JWS draft link above yielded a signature length of 86 base64 characters. The one @jcea says is incorrect is 96 characters long, and the one he says is correct is the first 50 characters of the incorrect one. I suppose in this case, these are base64 encodes of an ascii character array, and some of the values in each array are 3 digits, and some only 2.

luisgf commented 9 years ago

Hi All:

I’m working with the problem of ECDSA signatures and the validator issues and after that,i hope that the mistake can be fixed.

Without entering too much in ECC cryptography, in order to generate a ECDSA signature we need a function that passing some data and some parameters related to the curve, returns us a byte string containing the signature.

This signature is the representation of two internal parameters returned by the signing function, called “R” and “S” and is his raw format has a length of 64 bytes (32 bytes for R and 32 byte for S). The b64urlencode string of R and S concatenated has always a length of 86 chars for a curve prime256v1 signature. JWS draft for ECDSA (http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-11#page-34) is pristine, signatures should be the results of apply a base64url function to the concatenation of raw R and S parameters.

Now i will like talk about the mechanisms needed for transfer a signature that is, signature encodings. We can use directly the raw signature without any problems but that will cause us many interops problems, this is the reason for use a standard encoding mechanisms like ASN.1

ASN.1 is a terrible and complex format that should be eradicated from the face of earth, but unfortunately is common used that is capable of describe rules and structures for representing, encoding and transmitting data in the computer-world.

Ok, now i will create two files with the content of the assertion body and signature, called body.txt and signature.txt, then i start the research.

body.txt contains this:

eyJhbGciOiAiRVMyNTYifQ.eyJpc3N1ZWRPbiI6IDE0MTg5NDI0NjgsICJ1aWQiOiAiZGFhNTNlNWI1NGVmZmJlNWQ0OWNmNWEzMzU1YjQxYWRkMDc3MTdjNiIsICJpbWFnZSI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3BvbmVudGUyMDE0LnN2ZyIsICJ2ZXJpZnkiOiB7InR5cGUiOiAic2lnbmVkIiwgInVybCI6ICJodHRwczovL29wZW5iYWRnZXMuZXMucHl0aG9uLm9yZy9weXRob24tbWFkcmlkL3ZlcmlmeV9lY2Nfa2V5X29wZW5iYWRnZXMtdmFsaWRhdG9yX2lzc3VlXzMwLnBlbSJ9LCAiYmFkZ2UiOiAiaHR0cHM6Ly9vcGVuYmFkZ2VzLmVzLnB5dGhvbi5vcmcvcHl0aG9uLW1hZHJpZC9wb25lbnRlMjAxNC5qc29uIiwgInJlY2lwaWVudCI6IHsic2FsdCI6ICJkOTQzNTZiYTdmYTdiZWU2MzViOTNmZGYyYzQ5ZTE3OSIsICJoYXNoZWQiOiAidHJ1ZSIsICJ0eXBlIjogImVtYWlsIiwgImlkZW50aXR5IjogInNoYTI1NiRhMDYwMDA0YTRlMzlkODBlOTQ2ODVhOWUyNzM1OWEzOGVkMjZiNjM4NTkzMDdlYWNiNTZiYTFjYzlhYjY4MGZjIn19

And signature.txt contains this:

luisgf@NCC1701B:~/ecc_bug_30$ hexdump -C signature.txt 
00000000  30 46 02 21 00 f6 39 9a  d2 56 82 94 7e d2 2e 55  |0F.!..9..V..~..U|
00000010  2f d4 eb 1e 0a 6c 01 b2  88 bd 75 59 bc 1c 9c 23  |/....l....uY...#|
00000020  3e eb b8 fd cc 02 21 00  c1 62 53 fc bd 1e 30 b9  |>.....!..bS...0.|
00000030  75 ac 1b 10 4c a8 33 02  e3 06 3a f1 1f 4b e6 98  |u...L.3...:..K..|
00000040  d5 39 fd ff a3 7d bd fc                           |.9...}..|
00000048

@jcea first example is an ASN.1 DER encoded signature that makes one that you can validate with openssl, but doesn’t follow the standard.

luisgf@NCC1701B:~/ecc_bug_30$ openssl asn1parse -in signature.txt -inform DER
    0:d=0  hl=2 l=  70 cons: SEQUENCE          
    2:d=1  hl=2 l=  33 prim: INTEGER           :F6399AD25682947ED22E552FD4EB1E0A6C01B288BD7559BC1C9C233EEBB8FDCC
   37:d=1  hl=2 l=  33 prim: INTEGER           :C16253FCBD1E30B975AC1B104CA83302E3063AF11F4BE698D539FDFFA37DBDFC

OpenSSL verification:

luisgf@NCC1701B:~/ecc_bug_30$ openssl dgst -verify verify_ecc_key_openbadges-validator_issue_30.pem -sha256 -signature signature.txt body.txt 
Verified OK

Second @jcea example in file “signature2.txt” is a ASN.1 DER encoded signature incomplete, then the error is normal.

00000000  30 46 02 21 00 f6 39 9a  d2 56 82 94 7e d2 2e 55  |0F.!..9..V..~..U|
00000010  2f d4 eb 1e 0a 6c 01 b2  88 bd 75 59 bc 1c 9c 23  |/....l....uY...#|
00000020  3e eb b8 fd cc                                    |>....|
00000025

OpenSSL verification:

  luisgf@NCC1701B:~/ecc_bug_30$ openssl asn1parse -in signature2.txt -inform DER
  Error in encoding
  140543284500128:error:0D07209B:asn1 encoding routines:ASN1_get_object:too   long:asn1_lib.c:142:

Then, what’s is happening with Mozilla OpenBadge validator?

The problem is simple. The validator is accepting assertion signatures in ASN.1 DER encoded but refuse the raw signatures. Here a script that I do to test the bug reported here.

luisgf@NCC1701B:~/ecc_bug_30$ ./ecc_key_reconstruction.py 
Signature: 'MEYCIQD2OZrSVoKUftIuVS_U6x4KbAGyiL11WbwcnCM-67j9zAIhAMFiU_y9HjC5dawbEEyoMwLjBjrxH0vmmNU5_f-jfb38'
[+] Signature OK

R(32): [246, 57, 154, 210, 86, 130, 148, 126, 210, 46, 85, 47, 212, 235, 30, 10, 108, 1, 178, 136, 189, 117, 89, 188, 28, 156, 35, 62, 235, 184, 253, 204]
R(int) 111370739573812679899589462252649015682126855554630909600409073489822168448460
R(hex) 0xf6399ad25682947ed22e552fd4eb1e0a6c01b288bd7559bc1c9c233eebb8fdcc

S(32): [193, 98, 83, 252, 189, 30, 48, 185, 117, 172, 27, 16, 76, 168, 51, 2, 227, 6, 58, 241, 31, 75, 230, 152, 213, 57, 253, 255, 163, 125, 189, 252]
S(int) 87470110447688481065818790327181361735553742990558703955001108432634915962364
S(hex) 0xc16253fcbd1e30b975ac1b104ca83302e3063af11f4be698d539fdffa37dbdfc

[!] This is the signature that should be valid:
JWS sign(86): '9jma0laClH7SLlUv1OseCmwBsoi9dVm8HJwjPuu4_czBYlP8vR4wuXWsGxBMqDMC4wY68R9L5pjVOf3_o329_A'

Conclusions:

Mozilla validator accepts DER encodings signatures but refuse RAW. The validator should be fixed to follow the standards specifications.

jcea commented 9 years ago

PING!!!!. Any progress?

ottonomy commented 9 years ago

I was hoping to take a look at it this weekend after your ping, but could not. I'll take another try tonight.

On Sat, Apr 25, 2015 at 7:10 PM, jcea notifications@github.com wrote:

PING!!!!. Any progress?

— Reply to this email directly or view it on GitHub https://github.com/mozilla/openbadges-validator/issues/30#issuecomment-96308929 .

jcea commented 9 years ago

PING PING!

jcea commented 9 years ago

PING PING PING!

ottonomy commented 9 years ago

Sorry I haven't been able to get this done myself. I talked to Mozilla this morning. They're going to dedicate resources to supporting a DigitalMe team to make some changes to the Backpack starting immediately. I'll try to get this on that team's first priority list as my favor for connecting them to Mozilla.

Nate

On Thu, Aug 6, 2015, 9:11 PM jcea notifications@github.com wrote:

PING PING PING!

— Reply to this email directly or view it on GitHub https://github.com/mozilla/openbadges-validator/issues/30#issuecomment-128591825 .

luisgf commented 9 years ago

Hello:

I'm submit a pull request with id #33 (https://github.com/mozilla/openbadges-validator/pull/33) that's solve the problem with ECDSA signatures. Please take a look.

jcea commented 8 years ago

PING!!!!. Losing faith... More than a year for a issue identified, diagnosed and with a pending pull request four months and counting...

Nate, could you possibly point me to somebody who can move this forward?

Thanks.

kc1116 commented 7 years ago

Are there any updates on this issue ?