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