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 | |
40 | namespace fido { |
41 | using namespace WebCore; |
42 | using namespace cbor; |
43 | |
44 | using UVAvailability = AuthenticatorSupportedOptions::UserVerificationAvailability; |
45 | |
46 | static 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 | |
58 | static 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 | |
69 | static 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 | |
82 | static 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 | |
90 | Vector<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 | |
135 | Vector<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 | |
175 | Vector<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 | |