fukamachi / jose

A JOSE implementation
32 stars 8 forks source link

Feature request: ES256 encryption #3

Open zapko opened 3 years ago

zapko commented 3 years ago

Thank you for this project and for other CL projects you have šŸ™šŸ¼ Itā€™s very inspiring to see amount of work that was done to support modern development in common lisp.

Iā€™m trying to start a package that will provide development tools around Appleā€™s AppstoreConnect API in Common Lisp and it requires JWT with ES256 encryption.

Is it possible to add it? Or maybe if you can provide a guidelines on what changes are required or were to start them I can try to do it myself, but Iā€™m still learning the language and donā€™t feel very confident about this path.

fukamachi commented 3 years ago

Thank you for your suggestion.

When I wrote this library, Ironclad, CL cryptography library, didn't have the support of ECDSA. But, it seems Ironclad finally got it? (https://github.com/sharplispers/ironclad/issues/33)

I can't start working on this because of my situation, so it'd be appreciated if you send me a PR. When you have some time, please look into this file: https://github.com/fukamachi/jose/blob/master/jws.lisp

zapko commented 3 years ago

Thank you for the hints! I'll check them out and see if I can find solution myself.

kloenk commented 3 years ago

@zapko I'm also working on apple api at the moment xD. did you got something working yet? should I try (I'm new to lisp, so not sure if I succeed)?

kloenk commented 3 years ago

As far as I see it, we can just use the rsa functions. But I'm at the moment unable to load a ec pem file.

zapko commented 3 years ago

I drafted out an implementation for a signing method https://github.com/fukamachi/jose/compare/master...zapko:es256 ,Ā but I'm having troubles testing it. It looks like asn1 and/or pem packages require updates to support EC keys.

kloenk commented 3 years ago

I think I read an :rsa somewhere in the code of pem. Also my Quicklisp cannot find pem, unsure if my ql is broken.

zapko commented 3 years ago

You have to clone it into ql:local-projects folder from https://github.com/fukamachi/pem.Ā It's not in the global registry. Same for asn1

zapko commented 3 years ago

I've managed to run it,Ā but the signature it produces is not correct:

 (jose:encode :es256
              (ironclad:make-private-key :secp256r1 
                                         :x (cl-base64:base64-string-to-usb8-array 
                                             (cdar (pem/parser:parse-file *ecdsa-private-key*)) 
                                             :uri nil))
              '(("hello" . "world")))

Not sure what exactly I'm doing wrong.

; Signing method
(defun ecdsa-sign-message (digest-spec private-key message &key (start 0) (end (length message)))
  (let ((digest (ironclad:digest-sequence digest-spec message :start start :end end)))
    (ironclad:sign-message private-key digest :start 0 :end (length digest))))
zapko commented 3 years ago

Yay, I've managed to make it work!

The problem was that I wasn't reading file with the private key correctly.

With this addition to pem package:

(defun read-private-ec-key (key)
  (let* ((der (cl-base64:base64-string-to-usb8-array key))
         (der-parsed (asn1:decode der))
         (x (cdr (caddar der-parsed)))) ; There should be a way to make it better, but I don't know how
    (ironclad:make-private-key :secp256r1 :x x)))

(defun read-from-file (pem)
  (let ((data (pem/parser:parse-file pem)))
    (let ((public-key (cdr (assoc "PUBLIC KEY" data :test #'string=)))
          (private-key (cdr (assoc "RSA PRIVATE KEY" data :test #'string=)))
          (private-ec-key (cdr (assoc "EC PRIVATE KEY" data :test #'string=))))
      (cond
        (public-key (read-public-key public-key))
        (private-key (read-private-key private-key))
        (private-ec-key (read-private-ec-key private-ec-key))))))

This produces verified signature:

(jose:encode :es256
              (pem:read-from-file  *ecdsa-private-key*) ; Path to key file
              '(("hello" . "world")))