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:
M | der.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)))