cl-rw

Layered streams for Common Lisp
git clone https://logand.com/git/cl-rw.git/
Log | Files | Refs

commit 8e2ec2f9f14fc40455a6994227248df4d8e9067d
parent 08efd6d9f21b422d9c7770709267fb20f81254d1
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sat, 20 Sep 2014 13:35:49 +0200

read and write pem files

Diffstat:
Mder.lisp | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 115 insertions(+), 2 deletions(-)

diff --git a/der.lisp b/der.lisp @@ -34,6 +34,11 @@ ;; http://tools.ietf.org/html/rfc5280 ;; http://www.ietf.org/rfc/rfc3280.txt ;; https://en.wikipedia.org/wiki/X.509 +;; https://www.sslshopper.com/ssl-converter.html +;; http://how2ssl.com/articles/working_with_pem_files/ +;; https://www.novell.com/support/kb/doc.php?id=7013103 +;; http://www.herongyang.com/Cryptography/Certificate-Format-PEM-on-Certificates.html +;; http://serverfault.com/questions/9708/what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file (defun octets-to-utf8-string (x) #-(or sbcl) @@ -371,6 +376,8 @@ ;;(decode (rw:reader '(3 4 6 #x6e #x5d #xc0))) ; '(:bit-string "011011100101110111") ;;(encode w '(bit-string "011011100101110111")) ;; '(3 4 6 #x6e #x5d #xc0) +;; http://serverfault.com/questions/9708/what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file + (defun read-pem-key (reader) (let ((x (rw:till reader '(#\return #\newline)))) (rw:skip reader) @@ -382,7 +389,8 @@ #\P #\R #\I #\V #\A #\T #\E #\space #\K #\E #\Y #\- #\- #\- #\- #\-)) - (prog1 (decode (rw.base64:decode-reader reader)) + (prog1 (cons 'private-key (decode (rw.base64:decode-reader reader))) + ;;(rw:till (rw:peek-reader (rw.base64:decode-reader reader))) (rw:skip reader) (assert (equal '(#\- #\- #\- #\- #\- @@ -397,7 +405,8 @@ #\B #\E #\G #\I #\N #\space #\C #\E #\R #\T #\I #\F #\I #\C #\A #\T #\E #\- #\- #\- #\- #\-)) - (prog1 (decode (rw.base64:decode-reader reader)) + (prog1 (cons 'certificate (decode (rw.base64:decode-reader reader))) + ;;(rw:till (rw:peek-reader (rw.base64:decode-reader reader))) (rw:skip reader) (assert (equal '(#\- #\- #\- #\- #\- @@ -416,5 +425,109 @@ collect (read-pem-key r))))) ;;(read-pem-file "~/sw/gvfs/test/files/testcert.pem") +;;(read-pem-file "/tmp/a.pem") +;;(read-pem-file "/tmp/b.pem") ;;openssl x509 -in ~/sw/gvfs/test/files/testcert.pem -noout -text +(defun wrap-line-writer (writer columns) + (let ((n 0)) + (lambda (x) + (if (<= (incf n) columns) + (funcall writer x) + (progn + (setq n 0) + (funcall writer #\newline)))))) + +(defun wrap-line-reader (reader columns) + (let ((n 0)) + (lambda () + (cond + ((<= (incf n) columns) + (rw:next reader)) + (t + (setq n 0) + #\newline))))) + +;; TODO write pem, wrap-line-writer 64 (76 normal) + +(defun decode-reader (reader) + (lambda () + (decode reader))) + +(defun encode-writer (writer) + (lambda (x) + (encode writer x))) + +(defun encode-reader (reader &optional buffer) + (let* (done + (n 0) + (b (or buffer + (make-array 42 :fill-pointer 0 :adjustable t))) + (w (rw:writer b))) + (lambda () + (unless done + (if (< n (length b)) + (prog1 (aref b n) + (incf n)) + (let ((x (rw:next reader))) + (cond + (x + (setq n 0) + (setf (fill-pointer b) 0) + (encode w x) + ;;(print b) + (prog1 (aref b n) + (incf n))) + (t + (setq done t) + nil)))))))) + +(defun write-pem-key (writer x) + (destructuring-bind (tag &rest data) x + (rw:copy (rw:reader (ecase tag + (private-key "-----BEGIN PRIVATE KEY-----") + (certificate "-----BEGIN CERTIFICATE-----"))) + writer) + (funcall writer #\newline) + (rw:copy (wrap-line-reader + (rw.base64:encode-reader + (rw:peek-reader (encode-reader (rw:reader (list data))))) + 64) + writer) + #+nil + (rw:copy (rw.base64:encode-reader + (rw:peek-reader (encode-reader (rw:reader x)))) + (wrap-line-writer (rw:char-writer s) 64)) + (funcall writer #\newline) + (rw:copy (rw:reader (ecase tag + (private-key "-----END PRIVATE KEY-----") + (certificate "-----END CERTIFICATE-----"))) + writer) + (funcall writer #\newline))) + +(defun write-pem-file (keys pathname &key if-does-not-exist if-exists) + (with-open-file (s pathname + :direction :output + :if-does-not-exist if-does-not-exist + :if-exists if-exists) + (dolist (x keys) + (write-pem-key (rw:char-writer s) x)))) + +;; diff -du ~/sw/gvfs/test/files/testcert.pem /tmp/b.pem +#+nil +(write-pem-file (read-pem-file "~/sw/gvfs/test/files/testcert.pem") + "/tmp/b.pem" + :if-does-not-exist :create + :if-exists :supersede) + +;;(print (read-pem-file "~/sw/gvfs/test/files/testcert.pem")) +;;(print (read-pem-file "/tmp/b.pem")) +;;(equalp (read-pem-file "~/sw/gvfs/test/files/testcert.pem") (read-pem-file "/tmp/b.pem")) + +;;(mapc 'read-pem-file (directory "/home/tomas/**/*.pem")) + +;; TODO some crt binary, some PEM +#+nil +(with-open-file (s "/usr/share/doc/dirmngr/examples/extra-certs/S-TRUSTQualSigOCSP2008-022.final.v3.509.crt" + :element-type '(unsigned-byte 8)) + (decode (rw:byte-reader s)))