1PasswordのPasskey対応を試す
1Passwordのブラウザ拡張を経由してPasskeyのデモが公開されたので試してみる。Blinkブラウザ(ChromeやEdge)で1Password拡張を使っていれば、以下から試せる。 今のところ、以下のサイト以外では使えない 。
対応サイトが限定されているのは、元々ブラウザ側に付いているWebAuthnプロンプトを回避する必要があるからだろう。逆に、1Passwordの拡張が入っていない状態では、上記のサイトからデモにサインインできない。
(ちなみに、User-agentをspoofするとFirefoxでも 問題なく 動作する 現時点では鍵フォーマットが違うので、Chrome側とFirefox側でアカウントを共用できない ようだ。)
UIの流れ
... 特にコレといったものはない。ポップアップが順番に出るだけで、特に確認等は実施されない。
登録されたPasskeyは1Passwordのデスクトップアプリ内にも表示される。
登録の中身
他のパスワードと同様PrivateKeyはエクスポートできるようだが、Base64urlエンコードっぽい事以外は詳細不明。
{
"overview": {
"title": "1Password",
"url": "https://www.future.1password.com/passkeys/#demo",
"ainfo": "okuoku",
"ps": 0,
"pbe": 0,
"pgrng": false,
"URLs": [
{
"l": "website",
"u": "https://www.future.1password.com/passkeys/#demo"
}
],
"passkeyId": "5oV4s1ZTzmq9684HbLTwxw"
},
"details": {
"sections": [],
"fields": [
{
"id": "identifier",
"type": "T",
"value": "okuoku",
"designation": "username"
}
],
"passkey": {
"type": "webauthn",
"createdAt": 1668915306,
"privateKey": "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6eJqYB-vu1mVeASi4A0IfUmuw237DQmKfwsUDp-810ShRANCAAQTShslzQJHqh0BjyYKzpdG09WSd5bNMFvf54TCxlQR8b15iKs6_QqycKiAbwaevTSQm0n3eKIQ-n_0j0x15Uca",
"userHandle": "tXaZwYhvQjK8AsYlL6Uh-Q"
}
},
"createdAt": "2022-11-20T03:35:07Z",
"updatedAt": "2022-11-20T03:35:07Z",
"faveIndex": 0,
"trashed": "N",
"templateUuid": "001",
"uuid": "cgg4d2h2gp3bbcimpjxyrx6gmi"
}
FirefoxでやるとJsonになった
いやどうなってんだよ。。 data-onepassword-extension-version="20229"
。
{
"overview": {
"title": "PassParcel",
"url": "https://www.future.1password.com/passkeys/#demo",
"ainfo": "okuoku",
"ps": 0,
"pbe": 0,
"pgrng": false,
"URLs": [
{
"l": "website",
"u": "https://www.future.1password.com/passkeys/#demo"
}
],
"icons": {
"detail": {
"fileId": "qssh3khpzjn4rix7ih7m5qu6gu",
"encryptionKey": {
"alg": "A256GCM",
"ext": true,
"k": "_j1Ez36E8vO2FX5l9MKeAvaBUEvqI2Jp_yGWUtub_UY",
"key_ops": [
"encrypt",
"decrypt"
],
"kty": "oct",
"kid": "5jw64t4ea7gxszlb2x2rspnoy4"
},
"nonce": "VxOj9X2ElUstnpWi",
"signingKey": {
"kid": "IFSVKMSHDNCSNIKSBMAFJSL5RE",
"key_ops": [
"encrypt",
"decrypt"
],
"alg": "A256GCM",
"ext": true,
"kty": "oct",
"k": "bj8l04UsCdah8-VL1QeByH6NojhH5uqYHnEEQtw308c"
}
}
},
"passkeyId": "MkBlbuEAdnBZNtVMhCwgkA"
},
"details": {
"sections": [],
"fields": [
{
"id": "identifier",
"type": "T",
"value": "okuoku",
"designation": "username"
}
],
"passkey": {
"type": "webauthn",
"createdAt": 1668919343,
"privateKey": "eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwiZCI6IkJQT18zb2lfa25vVmQ5RGZLYTFFcDYtWWNIZ25sSXRkUVl1ck9RWEk0QVUiLCJ4IjoibERHWU1KUVdySVlxWWdqNVcweWFqckJ6TFJZczJVdEZIRURGVUQ0Mkh1ZyIsInkiOiJEWkw3c1Qzeld4a2kzWWJ0SkdNUlFyUlljaDNlNDc3clFDamM0TFJfN2pFIiwiYWxnIjoiRVMyNTYifQ",
"userHandle": "tXaZwYhvQjK8AsYlL6Uh-Q"
}
},
"createdAt": "2022-11-20T04:42:23Z",
"updatedAt": "2022-11-20T04:42:23Z",
"faveIndex": 0,
"trashed": "N",
"templateUuid": "001",
"uuid": "hmnepyplxkv62fm2imp47gkhlu"
}
このprivateKeyは
{
"kty": "EC",
"crv": "P-256",
"d": "BPO_3oi_knoVd9DfKa1Ep6-YcHgnlItdQYurOQXI4AU",
"x": "lDGYMJQWrIYqYgj5W0yajrBzLRYs2UtFHEDFUD42Hug",
"y": "DZL7sT3zWxki3YbtJGMRQrRYch3e477rQCjc4LR_7jE",
"alg": "ES256"
}
普通のECDSA鍵。
WebAuthn的なやりとりは passkey.1passwordservices.com/register/start
に対して行っていて、
- チャレンジ
{
"handshakeId": "06376bf5-587f-4dcb-a478-d138aef1d223",
"challenge": {
"publicKey": {
"rp": {
"name": "www.future.1password.com",
"id": "www.future.1password.com"
},
"user": {
"id": "tXaZwYhvQjK8AsYlL6Uh-Q",
"name": "okuoku",
"displayName": "okuoku"
},
"challenge": "IpRL34-5Q-xv_FmylS8MZv_lNKNJ_zZPD_cv1ZW0Lys",
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 60000,
"attestation": "none",
"authenticatorSelection": {
"requireResidentKey": false,
"userVerification": "preferred"
},
"extensions": {
"uvm": true,
"credProps": true
}
}
}
}
- 応答
{
"handshake_id": "06376bf5-587f-4dcb-a478-d138aef1d223",
"credential": {
"rawId": "MkBlbuEAdnBZNtVMhCwgkA",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSXBSTDM0LTVRLXh2X0ZteWxTOE1adl9sTktOSl96WlBEX2N2MVpXMEx5cyIsIm9yaWdpbiI6Imh0dHBzOi8vd3d3LmZ1dHVyZS4xcGFzc3dvcmQuY29tIn0",
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViU8tjaTVbDIXO71HQYzC1ZvWdMfixEk0MJrAkqefcoVExdAAAAAB_yoiMBb0YovsnZZwO8KS4AEDJAZW7hAHZwWTbVTIQsIJClAQIDJiABIVgglDGYMJQWrIYqYgj5W0yajrBzLRYs2UtFHEDFUD42HugiWCANkvuxPfNbGSLdhu0kYxFCtFhyHd7jvutAKNzgtH_uMQ"
},
"id": "MkBlbuEAdnBZNtVMhCwgkA",
"type": "public-key",
"authenticatorAttachment": "cross-platform"
}
}
clientDataJSON
は、
{
"type": "webauthn.create",
"challenge": "IpRL34-5Q-xv_FmylS8MZv_lNKNJ_zZPD_cv1ZW0Lys",
"origin": "https://www.future.1password.com"
}
不安になる実装をしている
1Passwordは2段階認証可能であるサイトをリスト管理していて2段階認証が無効になっていると警告するようになっているが、同様にPasskeyが使えるサイトをリスト管理し、リストにあるサイト のみ 有効にするのではないだろうか。
実際1Passwordはpasskeyが使えるサイトのリストを公開している:
Dashlaneは既にWebAuthnをサポートしている
特にWebサイトを限っては居ないようだ。
KeepassXCにはWebAuthn対応のPRが出ている
KeepassXCのブラウザ拡張はホスト連携必須なので実装自体は単にメッセージをリレーするだけとなっている。 navigator.credentials
をoverrideしてhookする形式で、失敗したら元のものにfallbackする。