summaryrefslogtreecommitdiff
path: root/src/mulk/benki/genkey.clj
blob: cd84ba30be79e0b6d02c468fd09ae9231f04cd18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
(ns mulk.benki.genkey
  (:refer-clojure)
  (:use [clojure         core repl pprint]
        [hiccup          core page]
        [mulk.benki      config util db webutil]
        [clojure.core.match
         :only [match]]
        [noir            core]
        [clojure.java.jdbc :only [transaction do-commands]])
  (:require [noir.session      :as session]
            [noir.response     :as response]
            [noir.request      :as request]
            [clojure.java.jdbc :as sql]
            [com.twinql.clojure.http :as http])
  (:import [org.bouncycastle.jcajce.provider.asymmetric.rsa
            BCRSAPublicKey]
           [org.bouncycastle.cert
            X509v3CertificateBuilder
            X509CertificateHolder]
           [org.bouncycastle.operator
            DefaultSignatureAlgorithmIdentifierFinder
            DefaultDigestAlgorithmIdentifierFinder]
           [org.bouncycastle.operator.bc
            BcRSAContentSignerBuilder]
           [org.bouncycastle.asn1.x509
            X509Name
            X509Extension
            SubjectPublicKeyInfo
            GeneralName
            GeneralNames]
           [org.bouncycastle.asn1.x500
            X500Name]))



(defonce signing-keypair
  (-> (doto (org.bouncycastle.crypto.generators.RSAKeyPairGenerator.)
        (.init (org.bouncycastle.crypto.params.RSAKeyGenerationParameters.
                (BigInteger. "123") (java.security.SecureRandom.) 512 123)))
      (.generateKeyPair)))

(defonce cert-signer
  (let [sig-id     (.find (DefaultSignatureAlgorithmIdentifierFinder.) "SHA1withRSA")
        digest-id  (.find (DefaultDigestAlgorithmIdentifierFinder.) sig-id)
        ;;digest-id  (.find (DefaultDigestAlgorithmIdentifierFinder.) "SHA1")
        ]
    (-> (BcRSAContentSignerBuilder. sig-id digest-id)
        (.build (.getPrivate signing-keypair)))))

(defonce cert-serial
  (atom 1N))

(defn join-lines [s]
  (apply str (clojure.string/split s #"\n")))

(defn decode-spkac [spkac]
  (org.bouncycastle.mozilla.SignedPublicKeyAndChallenge.
   (ring.util.codec/base64-decode (join-lines spkac))))

(defmulti spkac-pubkey->map type)

(defmethod spkac-pubkey->map BCRSAPublicKey [pubkey]
  {:modulus  (.getModulus pubkey)
   :exponent (.getPublicExponent pubkey)})

(defn spkac-pubkey [creq]
  (spkac-pubkey->map
   (.getPublicKey creq "BC")))

(defn now []
  (java.util.Date.))

(defn twenty-years-from-now []
  (java.util.Date. (+ (* 20 3600 24 365 1000) (.getTime (now)))))

(defn sign-spkac [spkac user]
  (let [serial     (swap! cert-serial inc)
        pubkeyinfo (-> spkac
                       (.getPublicKeyAndChallenge)
                       (.getSubjectPublicKeyInfo))
        builder    (X509v3CertificateBuilder.
                    (X500Name. "CN=Guenologlyan Mages Association")
                    (java.math.BigInteger. (str serial))
                    (now)
                    (twenty-years-from-now)
                    (X500Name. (fmt nil "CN=Benki User (~a)" (user-nickname user)))
                    pubkeyinfo)]
    (.addExtension builder
                   X509Extension/subjectAlternativeName
                   true
                   (GeneralNames.
                    (GeneralName.
                     GeneralName/uniformResourceIdentifier
                     (link :profile user))))
    (.build builder cert-signer)))

(defpage "/genkey" []
  (redirect "/keys"))

(defpage [:post "/keys/register"] []
  (let [spkac-data (get-in (request/ring-request) [:params :key])
        spkac      (decode-spkac spkac-data)
        pubkey     (spkac-pubkey spkac)]
    (with-dbt
      (query "INSERT INTO rsa_keys (modulus, exponent) VALUES (?::NUMERIC, ?::NUMERIC) RETURNING 't'"
             (str (:modulus pubkey)) (str (:exponent pubkey)))
      (query "INSERT INTO user_rsa_keys (\"user\", modulus, exponent) VALUES (?, ?::NUMERIC, ?::NUMERIC) RETURNING 't'"
             *user* (str (:modulus pubkey)) (str (:exponent pubkey)))
      ;;(redirect (linkrel :keys))
      {:status  200
       :headers {"Content-Type" "application/x-x509-user-cert"}
       :body    (.getEncoded (sign-spkac spkac *user*))})))

(defpage "/keys" []
  (with-auth
    (layout {} "Key Management"
            [:p
             [:h2 "Your Keys"]
             [:table
              {:style "border: 1px solid #000"
               :border "1"}
              [:thead
               [:th {:style "text-align: left"} "Exponent"]
               [:th {:style "text-align: left"} "Modulus"]]
              [:tbody
               (with-dbt
                 (for [{e :exponent, m :modulus}
                       (query "select * from user_rsa_keys where \"user\" = ?" *user*)]
                   [:tr
                    [:td e]
                    [:td m]]))]]]
            [:p
             [:h2 "Generate a Key Pair"]
             [:h3 "RSA"]
             [:form {:method "POST", :action (linkrel :keys :register)}
              [:keygen {:name "key", :keytype "RSA"}]
              [:input {:type "submit" :value "Generate"}]]
             [:h3 "ECDSA"
              [:form {:method "POST", :href (linkrel :keys :register)}
               [:keygen {:name "key", :keytype "EC", :keyparams "secp521r1"}]
               [:input {:type "submit" :value "Generate"}]]]])))