1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "cbor-cpp/src/cbor.h"
8 #include "mozilla/dom/WebAuthnCBORUtil.h"
9 #include "mozilla/dom/WebAuthnUtil.h"
10
11 namespace mozilla {
12 namespace dom {
13
CBOREncodePublicKeyObj(const CryptoBuffer & aPubKeyBuf,CryptoBuffer & aPubKeyObj)14 nsresult CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
15 /* out */ CryptoBuffer& aPubKeyObj) {
16 mozilla::dom::CryptoBuffer xBuf, yBuf;
17 nsresult rv = U2FDecomposeECKey(aPubKeyBuf, xBuf, yBuf);
18 if (NS_FAILED(rv)) {
19 return rv;
20 }
21
22 // COSE_Key object. See https://tools.ietf.org/html/rfc8152#section-7
23 cbor::output_dynamic cborPubKeyOut;
24 cbor::encoder encoder(cborPubKeyOut);
25 encoder.write_map(5);
26 {
27 encoder.write_int(1); // kty
28 encoder.write_int(2); // EC2
29 encoder.write_int(3); // alg
30 encoder.write_int(-7); // ES256
31
32 // See https://tools.ietf.org/html/rfc8152#section-13.1
33 encoder.write_int(-1); // crv
34 encoder.write_int(1); // P-256
35 encoder.write_int(-2); // x
36 encoder.write_bytes(xBuf.Elements(), xBuf.Length());
37 encoder.write_int(-3); // y
38 encoder.write_bytes(yBuf.Elements(), yBuf.Length());
39 }
40
41 if (!aPubKeyObj.Assign(cborPubKeyOut.data(), cborPubKeyOut.size())) {
42 return NS_ERROR_OUT_OF_MEMORY;
43 }
44 return NS_OK;
45 }
46
CBOREncodeFidoU2FAttestationObj(const CryptoBuffer & aAuthDataBuf,const CryptoBuffer & aAttestationCertBuf,const CryptoBuffer & aSignatureBuf,CryptoBuffer & aAttestationObj)47 nsresult CBOREncodeFidoU2FAttestationObj(
48 const CryptoBuffer& aAuthDataBuf, const CryptoBuffer& aAttestationCertBuf,
49 const CryptoBuffer& aSignatureBuf,
50 /* out */ CryptoBuffer& aAttestationObj) {
51 /*
52 Attestation Object, encoded in CBOR (description is CDDL)
53
54 attObj = {
55 authData: bytes,
56 $$attStmtType
57 }
58 $$attStmtType //= (
59 fmt: "fido-u2f",
60 attStmt: u2fStmtFormat
61 )
62 u2fStmtFormat = {
63 x5c: [ attestnCert: bytes, * (caCert: bytes) ],
64 sig: bytes
65 }
66 */
67 cbor::output_dynamic cborAttOut;
68 cbor::encoder encoder(cborAttOut);
69 encoder.write_map(3);
70 {
71 encoder.write_string("fmt");
72 encoder.write_string("fido-u2f");
73
74 encoder.write_string("attStmt");
75 encoder.write_map(2);
76 {
77 encoder.write_string("sig");
78 encoder.write_bytes(aSignatureBuf.Elements(), aSignatureBuf.Length());
79
80 encoder.write_string("x5c");
81 // U2F wire protocol can only deliver 1 certificate, so it's never a chain
82 encoder.write_array(1);
83 encoder.write_bytes(aAttestationCertBuf.Elements(),
84 aAttestationCertBuf.Length());
85 }
86
87 encoder.write_string("authData");
88 encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
89 }
90
91 if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
92 return NS_ERROR_OUT_OF_MEMORY;
93 }
94 return NS_OK;
95 }
96
CBOREncodeNoneAttestationObj(const CryptoBuffer & aAuthDataBuf,CryptoBuffer & aAttestationObj)97 nsresult CBOREncodeNoneAttestationObj(const CryptoBuffer& aAuthDataBuf,
98 /* out */ CryptoBuffer& aAttestationObj) {
99 /*
100 Attestation Object, encoded in CBOR (description is CDDL)
101
102 $$attStmtType //= (
103 fmt: "none",
104 attStmt: emptyMap
105 )
106
107 emptyMap = {}
108 */
109 cbor::output_dynamic cborAttOut;
110 cbor::encoder encoder(cborAttOut);
111 encoder.write_map(3);
112 {
113 encoder.write_string("fmt");
114 encoder.write_string("none");
115
116 encoder.write_string("attStmt");
117 encoder.write_map(0);
118
119 encoder.write_string("authData");
120 encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
121 }
122
123 if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
124 return NS_ERROR_OUT_OF_MEMORY;
125 }
126 return NS_OK;
127 }
128
129 } // namespace dom
130 } // namespace mozilla
131