From 9ba0960d712884f08fef754fb00c2491a3276965 Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Fri, 4 Jun 2021 11:40:34 +0200 Subject: [PATCH] improve credential handling for e2e Signed-off-by: Michele Balistreri --- src/status_im/keycard/simulated_keycard.cljs | 295 ++++++++++--------- 1 file changed, 151 insertions(+), 144 deletions(-) diff --git a/src/status_im/keycard/simulated_keycard.cljs b/src/status_im/keycard/simulated_keycard.cljs index a8d0175730..f330eb9f4b 100644 --- a/src/status_im/keycard/simulated_keycard.cljs +++ b/src/status_im/keycard/simulated_keycard.cljs @@ -12,6 +12,11 @@ [taoensso.timbre :as log] [status-im.multiaccounts.create.core :as multiaccounts.create])) +(def kk1-password "000000") +(def default-pin "111111") +(def default-puk "000000000000") +(def account-password (ethereum/sha3 "no password")) + (def initial-state {:card-connected? false :nfc-started? false @@ -27,7 +32,7 @@ (defn connect-selected-card [] (swap! state assoc :application-info {:free-pairing-slots 5 - :app-version "2.2" + :app-version "3.0" :secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", :instance-uid "1b360b10a9a68b7d494e8f059059f118" :paired? true @@ -36,6 +41,7 @@ :pin-retry-counter 3 :puk-retry-counter 5 :key-uid (get-in @re-frame.db/app-db [:multiaccounts/login :key-uid])}) + (swap! state assoc :pin default-pin :puk default-puk :password kk1-password) (connect-card)) (def initialization (atom false)) @@ -44,7 +50,7 @@ (reset! initialization false) (swap! state assoc :application-info {:free-pairing-slots 5 - :app-version "2.2" + :app-version "3.0" :secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", :instance-uid "1b360b10a9a68b7d494e8f059059f118" :paired? false @@ -53,6 +59,7 @@ :pin-retry-counter 3 :puk-retry-counter 5 :key-uid "0x16839e8b1b8a395acb18100c7e2b161701c225adf31eefa02114099b4d81a30b"}) + (swap! state assoc :pin default-pin :puk default-puk :password kk1-password) (connect-card)) (defn disconnect-card [] @@ -67,6 +74,27 @@ (when f (utils/set-timeout f 500))) +(defn pin-error [] + #js {:code "EUNSPECIFIED" + :message (str "Unexpected error SW, 0x63C" (get-in @state [:application-info :pin-retry-counter]))}) + +(defn puk-error [] + #js {:code "EUNSPECIFIED" + :message (str "Unexpected error SW, 0x63C" (get-in @state [:application-info :puk-retry-counter]))}) + +(defn with-pin [pin on-failure on-valid] + (if (= pin (get @state :pin)) + (do + (swap! state update :application-info assoc + :pin-retry-counter 3 + :puk-retry-counter 5) + (later on-valid)) + (do + (swap! state update-in + [:application-info :pin-retry-counter] + (fnil dec 3)) + (later #(on-failure (pin-error)))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn start-nfc [{:keys [on-success]}] @@ -119,24 +147,28 @@ (log/debug "get-application-info") (later #(on-success (get @state :application-info)))) -(defn factory-reset [_]) +(defn factory-reset [args] + (log/debug "factory-reset") + (reset-state) + (get-application-info args)) + (defn install-applet [_]) (defn install-cash-applet [_]) -(def kk1-password "000000") -(def default-puk "000000000000") (defn init-card [{:keys [pin on-success]}] (reset! initialization true) (swap! state assoc :application-info {:free-pairing-slots 5 - :app-version "2.2" + :app-version "3.0" :secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", :key-uid "", :instance-uid "1b360b10a9a68b7d494e8f059059f118" :paired? false :has-master-key? false + :pin-retry-counter 3 + :puk-retry-counter 5 :initialized? true}) - (swap! state assoc :pin pin) + (swap! state assoc :pin pin :puk default-puk :password kk1-password) (later #(on-success {:password kk1-password :puk default-puk @@ -144,11 +176,9 @@ (defn install-applet-and-init-card [_]) -(def kk1-pair "ADEol+GCD67EO7zU6ko0DNK7XrNs9w2+h9GxcibNY4yf") - (def derived-acc (atom nil)) -(defn multiaccount->keys [pin data] +(defn multiaccount->keys [data] (let [{:keys [selected-id multiaccounts root-key derived]} data @@ -161,7 +191,7 @@ whisper (get derived constants/path-whisper-keyword) wallet (get derived constants/path-default-wallet-keyword) wallet-root (get derived constants/path-wallet-root-keyword) - password (ethereum/sha3 pin) + password account-password response {:key-uid key-uid :encryption-public-key password :address address @@ -206,7 +236,7 @@ (reset! derived-acc {:root-key root-data :derived derived-data-extended}))))))))))) - (when (= password kk1-password) + (when (= password (get @state :password)) (do (swap! state assoc-in [:application-info :paired?] true) (later #(on-success (str (rand-int 10000000))))))) @@ -215,7 +245,6 @@ [{:keys [pin on-success]}] (when (= pin (get @state :pin)) (let [[id response] (multiaccount->keys - pin (:intro-wizard @re-frame.db/app-db))] (log/debug "[simulated kk] generate-and-load-key response" response) (swap! state assoc-in @@ -227,12 +256,12 @@ constants/path-eip1581 constants/path-whisper constants/path-default-wallet] - (ethereum/sha3 pin) + account-password #(on-success response))))) (defn unblock-pin [{:keys [puk on-success on-failure]}] - (if (= puk default-puk) + (if (= puk (get @state :puk)) (do (swap! state update :application-info assoc :pin-retry-counter 3 @@ -243,27 +272,29 @@ [:application-info :puk-retry-counter] (fnil dec 5)) (later - #(on-failure - #js {:code "EUNSPECIFIED" - :message "Unexpected error SW, 0x63C2"}))))) + #(on-failure (puk-error)))))) (defn verify-pin [{:keys [pin on-success on-failure]}] - (if (= pin (get @state :pin)) - (later #(on-success 3)) - (do - (swap! state update-in - [:application-info :pin-retry-counter] - (fnil dec 3)) - (later #(on-failure - #js {:code "EUNSPECIFIED" - :message "Unexpected error SW, 0x63C2"}))))) + (with-pin pin on-failure #(on-success 3))) + +(defn change-pin [{:keys [current-pin new-pin on-success on-failure]}] + (with-pin current-pin on-failure + (fn [] + (swap! state assoc :pin new-pin) + (on-success)))) + +(defn change-puk [{:keys [pin puk on-success on-failure]}] + (with-pin pin on-failure + (fn [] + (swap! state assoc :puk puk) + (on-success)))) + +(defn change-pairing [{:keys [pin pairing on-success on-failure]}] + (with-pin pin on-failure + (fn [] + (swap! state assoc :password pairing) + (on-success)))) -(defn change-pin [args] - (log/warn "change-pin not implemented" args)) -(defn change-puk [args] - (log/warn "change-puk not implemented" args)) -(defn change-pairing [args] - (log/warn "change-pairing not implemented" args)) (defn unpair [args] (log/warn "unpair not implemented" args)) (defn delete [args] @@ -280,124 +311,100 @@ path)) (defn export-key [{:keys [pin on-success on-failure]}] - (let [{:keys [key-uid wallet-root-address]} - (get @re-frame.db/app-db :multiaccount) - accounts (get @re-frame.db/app-db :multiaccount/accounts) - hashed-password (ethereum/sha3 pin) - path-num (inc (get-in @re-frame.db/app-db [:multiaccount :latest-derived-path])) - path (str "m/" path-num)] - (status/multiaccount-load-account - wallet-root-address - hashed-password - (fn [value] - (let [{:keys [id error]} (types/json->clj value)] - (if error - (re-frame/dispatch [::new-account-error :password-error error]) - (status/multiaccount-derive-addresses - id - [path] - (fn [derived] - (let [derived-address (get-in (types/json->clj derived) [(keyword path) :address])] - (if (some #(= derived-address (get % :address)) accounts) - (re-frame/dispatch [::new-account-error :account-error (i18n/label :t/account-exists-title)]) - (status/multiaccount-store-derived - id - key-uid - [path] - hashed-password - (fn [result] - (let [{:keys [error] :as result} (types/json->clj result) - {:keys [publicKey]} (get result (keyword path))] - (if error - (on-failure error) - (on-success publicKey))))))))))))))) + (with-pin pin on-failure + #(let [{:keys [key-uid wallet-root-address]} + (get @re-frame.db/app-db :multiaccount) + accounts (get @re-frame.db/app-db :multiaccount/accounts) + hashed-password account-password + path-num (inc (get-in @re-frame.db/app-db [:multiaccount :latest-derived-path])) + path (str "m/" path-num)] + (status/multiaccount-load-account + wallet-root-address + hashed-password + (fn [value] + (let [{:keys [id error]} (types/json->clj value)] + (if error + (re-frame/dispatch [::new-account-error :password-error error]) + (status/multiaccount-derive-addresses + id + [path] + (fn [derived] + (let [derived-address (get-in (types/json->clj derived) [(keyword path) :address])] + (if (some (fn [a] (= derived-address (get a :address))) accounts) + (re-frame/dispatch [::new-account-error :account-error (i18n/label :t/account-exists-title)]) + (status/multiaccount-store-derived + id + key-uid + [path] + hashed-password + (fn [result] + (let [{:keys [error] :as result} (types/json->clj result) + {:keys [publicKey]} (get result (keyword path))] + (if error + (on-failure error) + (on-success publicKey)))))))))))))))) (defn unpair-and-delete [_]) -;; It is a bit complicated to verify password before we have multiaccs main -;; wallet address, so we just define a set of "allowed" pins -(def allowed-pins - #{"121212" "111111" "222222" "123123"}) - (defn get-keys [{:keys [on-success on-failure pin]}] - (if (contains? allowed-pins pin) - (do - (swap! state assoc :pin pin) - (later - (if @derived-acc - (let [[id keys] (multiaccount->keys pin @derived-acc)] - (swap! state assoc-in - [:application-info :key-uid] (:key-uid keys)) - (status/multiaccount-store-derived - id - (:key-uid keys) - [constants/path-wallet-root - constants/path-eip1581 - constants/path-whisper - constants/path-default-wallet] - (ethereum/sha3 pin) - #(on-success keys))) - #(on-success - {:key-uid (get-in @state [:application-info :key-uid]) - :encryption-public-key (ethereum/sha3 pin)})))) - (do - (log/debug "Incorrect PIN" pin) - (swap! state update-in - [:application-info :pin-retry-counter] - (fnil dec 3)) - (later - #(on-failure - #js {:code "EUNSPECIFIED" - :message "Unexpected error SW, 0x63C2"}))))) + (with-pin pin on-failure + (if @derived-acc + (let [[id keys] (multiaccount->keys @derived-acc)] + (swap! state assoc-in + [:application-info :key-uid] (:key-uid keys)) + (status/multiaccount-store-derived + id + (:key-uid keys) + [constants/path-wallet-root + constants/path-eip1581 + constants/path-whisper + constants/path-default-wallet] + account-password + #(on-success keys))) + #(on-success + {:key-uid (get-in @state [:application-info :key-uid]) + :instance-uid (get-in @state [:application-info :instance-uid]) + :encryption-public-key account-password})))) (def import-keys get-keys) (defn sign [{:keys [pin hash data path typed? on-success on-failure]}] - (if (= pin (get @state :pin)) - (later - #(let [address - (if path - (reduce - (fn [_ {:keys [address] :as acc}] - (when (= path (:path acc)) - (reduced address))) - nil - (:multiaccount/accounts @re-frame.db/app-db)) - (-> (:multiaccount/accounts @re-frame.db/app-db) - first - :address)) - password (ethereum/sha3 pin)] - (if-not typed? - (let [params (types/clj->json - {:account address - :password password - :data (or data (str "0x" hash))})] - (status/sign-message - params - (fn [res] - (let [signature (-> res - types/json->clj - :result - ethereum/normalized-hex)] - (on-success signature))))) - (status/sign-typed-data - data - address - password - (fn [res] - (let [signature (-> res - types/json->clj - :result - ethereum/normalized-hex)] - (on-success signature))))))) - (do - (swap! state update-in - [:application-info :pin-retry-counter] - (fnil dec 3)) - (later - #(on-failure - #js {:code "EUNSPECIFIED" - :message "Unexpected error SW, 0x63C2"}))))) + (with-pin pin on-failure + #(let [address + (if path + (reduce + (fn [_ {:keys [address] :as acc}] + (when (= path (:path acc)) + (reduced address))) + nil + (:multiaccount/accounts @re-frame.db/app-db)) + (-> (:multiaccount/accounts @re-frame.db/app-db) + first + :address)) + password account-password] + (if-not typed? + (let [params (types/clj->json + {:account address + :password password + :data (or data (str "0x" hash))})] + (status/sign-message + params + (fn [res] + (let [signature (-> res + types/json->clj + :result + ethereum/normalized-hex)] + (on-success signature))))) + (status/sign-typed-data + data + address + password + (fn [res] + (let [signature (-> res + types/json->clj + :result + ethereum/normalized-hex)] + (on-success signature)))))))) (defn sign-typed-data [args] (log/warn "sign-typed-data not implemented" args)) @@ -417,7 +424,7 @@ (defn send-transaction-with-signature [{:keys [transaction on-completed]}] - (status/send-transaction transaction (ethereum/sha3 (:pin @state)) on-completed)) + (status/send-transaction transaction account-password on-completed)) (defrecord SimulatedKeycard [] keycard/Keycard