1// Copyright 2017 The Chromium Authors. All rights reserved.
2// Copyright (C) 2018 Apple Inc. All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "config.h"
31#include "DeviceRequestConverter.h"
32
33#if ENABLE(WEB_AUTHN)
34
35#include "CBORWriter.h"
36#include "PublicKeyCredentialCreationOptions.h"
37#include "PublicKeyCredentialRequestOptions.h"
38#include <wtf/Vector.h>
39
40namespace fido {
41using namespace WebCore;
42using namespace cbor;
43
44using UVAvailability = AuthenticatorSupportedOptions::UserVerificationAvailability;
45
46static CBORValue convertRpEntityToCBOR(const PublicKeyCredentialCreationOptions::RpEntity& rpEntity)
47{
48 CBORValue::MapValue rpMap;
49 rpMap.emplace(CBORValue(kEntityNameMapKey), CBORValue(rpEntity.name));
50 if (!rpEntity.icon.isEmpty())
51 rpMap.emplace(CBORValue(kIconUrlMapKey), CBORValue(rpEntity.icon));
52 if (!rpEntity.id.isEmpty())
53 rpMap.emplace(CBORValue(kEntityIdMapKey), CBORValue(rpEntity.id));
54
55 return CBORValue(WTFMove(rpMap));
56}
57
58static CBORValue convertUserEntityToCBOR(const PublicKeyCredentialCreationOptions::UserEntity& userEntity)
59{
60 CBORValue::MapValue userMap;
61 userMap.emplace(CBORValue(kEntityNameMapKey), CBORValue(userEntity.name));
62 if (!userEntity.icon.isEmpty())
63 userMap.emplace(CBORValue(kIconUrlMapKey), CBORValue(userEntity.icon));
64 userMap.emplace(CBORValue(kEntityIdMapKey), CBORValue(userEntity.idVector));
65 userMap.emplace(CBORValue(kDisplayNameMapKey), CBORValue(userEntity.displayName));
66 return CBORValue(WTFMove(userMap));
67}
68
69static CBORValue convertParametersToCBOR(const Vector<PublicKeyCredentialCreationOptions::Parameters>& parameters)
70{
71 CBORValue::ArrayValue credentialParamArray;
72 credentialParamArray.reserveInitialCapacity(parameters.size());
73 for (const auto& credential : parameters) {
74 CBORValue::MapValue cborCredentialMap;
75 cborCredentialMap.emplace(CBORValue(kCredentialTypeMapKey), CBORValue(publicKeyCredentialTypeToString(credential.type)));
76 cborCredentialMap.emplace(CBORValue(kCredentialAlgorithmMapKey), CBORValue(credential.alg));
77 credentialParamArray.append(WTFMove(cborCredentialMap));
78 }
79 return CBORValue(WTFMove(credentialParamArray));
80}
81
82static CBORValue convertDescriptorToCBOR(const PublicKeyCredentialDescriptor& descriptor)
83{
84 CBORValue::MapValue cborDescriptorMap;
85 cborDescriptorMap[CBORValue(kCredentialTypeKey)] = CBORValue(publicKeyCredentialTypeToString(descriptor.type));
86 cborDescriptorMap[CBORValue(kCredentialIdKey)] = CBORValue(descriptor.idVector);
87 return CBORValue(WTFMove(cborDescriptorMap));
88}
89
90Vector<uint8_t> encodeMakeCredenitalRequestAsCBOR(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions& options, UVAvailability uvCapability)
91{
92 CBORValue::MapValue cborMap;
93 cborMap[CBORValue(1)] = CBORValue(hash);
94 cborMap[CBORValue(2)] = convertRpEntityToCBOR(options.rp);
95 cborMap[CBORValue(3)] = convertUserEntityToCBOR(options.user);
96 cborMap[CBORValue(4)] = convertParametersToCBOR(options.pubKeyCredParams);
97 if (!options.excludeCredentials.isEmpty()) {
98 CBORValue::ArrayValue excludeListArray;
99 for (const auto& descriptor : options.excludeCredentials)
100 excludeListArray.append(convertDescriptorToCBOR(descriptor));
101 cborMap[CBORValue(5)] = CBORValue(WTFMove(excludeListArray));
102 }
103
104 CBORValue::MapValue optionMap;
105 if (options.authenticatorSelection) {
106 // Resident keys are not supported by default.
107 if (options.authenticatorSelection->requireResidentKey)
108 optionMap[CBORValue(kResidentKeyMapKey)] = CBORValue(true);
109
110 // User verification is not required by default.
111 bool requireUserVerification = false;
112 switch (options.authenticatorSelection->userVerification) {
113 case UserVerificationRequirement::Required:
114 requireUserVerification = true;
115 break;
116 case UserVerificationRequirement::Preferred:
117 requireUserVerification = uvCapability == UVAvailability::kNotSupported ? false : true;
118 break;
119 case UserVerificationRequirement::Discouraged:
120 requireUserVerification = false;
121 }
122 optionMap[CBORValue(kUserVerificationMapKey)] = CBORValue(requireUserVerification);
123 }
124 if (!optionMap.empty())
125 cborMap[CBORValue(7)] = CBORValue(WTFMove(optionMap));
126
127 auto serializedParam = CBORWriter::write(CBORValue(WTFMove(cborMap)));
128 ASSERT(serializedParam);
129
130 Vector<uint8_t> cborRequest({ static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorMakeCredential) });
131 cborRequest.appendVector(*serializedParam);
132 return cborRequest;
133}
134
135Vector<uint8_t> encodeGetAssertionRequestAsCBOR(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions& options, UVAvailability uvCapability)
136{
137 CBORValue::MapValue cborMap;
138 cborMap[CBORValue(1)] = CBORValue(options.rpId);
139 cborMap[CBORValue(2)] = CBORValue(hash);
140
141 if (!options.allowCredentials.isEmpty()) {
142 CBORValue::ArrayValue allowListArray;
143 for (const auto& descriptor : options.allowCredentials)
144 allowListArray.append(convertDescriptorToCBOR(descriptor));
145 cborMap[CBORValue(3)] = CBORValue(WTFMove(allowListArray));
146 }
147
148 CBORValue::MapValue optionMap;
149 // User verification is not required by default.
150 bool requireUserVerification = false;
151 switch (options.userVerification) {
152 case UserVerificationRequirement::Required:
153 requireUserVerification = true;
154 break;
155 case UserVerificationRequirement::Preferred:
156 requireUserVerification = uvCapability == UVAvailability::kNotSupported ? false : true;
157 break;
158 case UserVerificationRequirement::Discouraged:
159 requireUserVerification = false;
160 }
161 optionMap[CBORValue(kUserVerificationMapKey)] = CBORValue(requireUserVerification);
162 optionMap[CBORValue(kUserPresenceMapKey)] = CBORValue(true);
163
164 if (!optionMap.empty())
165 cborMap[CBORValue(5)] = CBORValue(WTFMove(optionMap));
166
167 auto serializedParam = CBORWriter::write(CBORValue(WTFMove(cborMap)));
168 ASSERT(serializedParam);
169
170 Vector<uint8_t> cborRequest({ static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorGetAssertion) });
171 cborRequest.appendVector(*serializedParam);
172 return cborRequest;
173}
174
175Vector<uint8_t> encodeEmptyAuthenticatorRequest(CtapRequestCommand cmd)
176{
177 return { static_cast<uint8_t>(cmd) };
178}
179
180} // namespace fido
181
182#endif // ENABLE(WEB_AUTHN)
183