Skip to content

Commit b3ecca7

Browse files
committed
minor changes
1 parent 027b74e commit b3ecca7

File tree

7 files changed

+61
-50
lines changed

7 files changed

+61
-50
lines changed

Sources/WebAuthn/Authenticator/AttestationObject/AttestationStatementVerification.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the WebAuthn Swift open source project
4+
//
5+
// Copyright (c) 2022 the WebAuthn Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of WebAuthn Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
115
import SwiftCBOR
216
import Crypto
317

Sources/WebAuthn/Ceremonies/Registration/ParsedCredentialCreationResponse.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,27 @@ struct ParsedCredentialCreationResponse {
3030
init(from rawResponse: CredentialCreationResponse) throws {
3131
id = rawResponse.id
3232

33-
guard let decodedRawID = rawResponse.rawID.base64URLDecodedData else { throw WebAuthnError.invalidRawID }
33+
guard let decodedRawID = rawResponse.rawID.base64URLDecodedData else {
34+
throw WebAuthnError.invalidRawID
35+
}
3436
rawID = decodedRawID
3537

36-
guard rawResponse.type == "public-key" else { throw WebAuthnError.invalidCredentialCreationType }
38+
guard rawResponse.type == "public-key" else {
39+
throw WebAuthnError.invalidCredentialCreationType
40+
}
3741
type = rawResponse.type
3842

3943
clientExtensionResults = rawResponse.clientExtensionResults
4044
raw = rawResponse.attestationResponse
4145
response = try ParsedAuthenticatorAttestationResponse(from: raw)
4246
}
4347

44-
func verify(storedChallenge: String, verifyUser: Bool, relyingPartyID: String, relyingPartyOrigin: String) throws {
48+
func verify(
49+
storedChallenge: URLEncodedBase64,
50+
verifyUser: Bool,
51+
relyingPartyID: String,
52+
relyingPartyOrigin: String
53+
) throws {
4554
// Step 7. - 9.
4655
try response.clientData.verify(
4756
storedChallenge: storedChallenge,
@@ -63,5 +72,10 @@ struct ParsedCredentialCreationResponse {
6372
verificationRequired: verifyUser,
6473
clientDataHash: hash
6574
)
75+
76+
// Step 23.
77+
guard rawID.count <= 1023 else {
78+
throw WebAuthnError.credentialIDTooBig
79+
}
6680
}
6781
}

Sources/WebAuthn/Ceremonies/Registration/PublicKeyCredentialCreationOptions.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ import Foundation
1818
/// Contains a PublicKeyCredentialCreationOptions object specifying the desired attributes of the
1919
/// to-be-created public key credential.
2020
public struct PublicKeyCredentialCreationOptions: Codable {
21-
/// Base64-encoded challenge string
22-
public let challenge: String
21+
public let challenge: EncodedBase64
2322
public let user: PublicKeyCredentialUserEntity
2423
public let relyingParty: PublicKeyCredentialRpEntity
2524
public let publicKeyCredentialParameters: [PublicKeyCredentialParameters]

Sources/WebAuthn/Helpers/Base64Utilities.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ import Foundation
1616
import Logging
1717

1818
public typealias URLEncodedBase64 = String
19+
public typealias EncodedBase64 = String
1920

2021
extension Array where Element == UInt8 {
2122
/// Encodes an array of bytes into a base64url-encoded string
2223
/// - Returns: A base64url-encoded string
2324
public func base64URLEncodedString() -> String {
2425
let base64String = Data(bytes: self, count: self.count).base64EncodedString()
25-
return base64String.replacingOccurrences(of: "+", with: "-")
26-
.replacingOccurrences(of: "/", with: "_")
27-
.replacingOccurrences(of: "=", with: "")
26+
return String.base64URL(fromBase64: base64String)
2827
}
2928

3029
/// Encodes an array of bytes into a base64 string
@@ -40,6 +39,12 @@ extension String {
4039
public static func base64(fromBase64URLEncoded base64URLEncoded: String) -> Self {
4140
return base64URLEncoded.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
4241
}
42+
43+
public static func base64URL(fromBase64 base64Encoded: String) -> Self {
44+
return base64Encoded.replacingOccurrences(of: "+", with: "-")
45+
.replacingOccurrences(of: "/", with: "_")
46+
.replacingOccurrences(of: "=", with: "")
47+
}
4348
}
4449

4550
extension String {

Sources/WebAuthn/SessionData.swift

Lines changed: 0 additions & 27 deletions
This file was deleted.

Sources/WebAuthn/WebAuthnError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public enum WebAuthnError: Error {
3131
case missingAttestedCredentialData
3232
case missingAttestationFormat
3333

34+
case credentialIDTooBig
35+
case credentialIDAlreadyExists
36+
3437
case invalidRawID
3538
case invalidCredentialCreationType
3639
case invalidClientDataJSON

Sources/WebAuthn/WebAuthnManager.swift

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public struct WebAuthnManager {
3030
}
3131

3232
/// Generate a new set of registration data to be sent to the client and authenticator.
33-
public func beginRegistration(user: User) throws -> (PublicKeyCredentialCreationOptions, SessionData) {
33+
public func beginRegistration(user: User) throws -> PublicKeyCredentialCreationOptions {
3434
guard let base64ID = user.userID.data(using: .utf8)?.base64EncodedString() else {
3535
throw WebAuthnManagerError.base64EncodingFailed
3636
}
@@ -40,38 +40,33 @@ public struct WebAuthnManager {
4040

4141
let challenge = try generateChallengeString()
4242

43-
let options = PublicKeyCredentialCreationOptions(
43+
return PublicKeyCredentialCreationOptions(
4444
challenge: challenge.base64EncodedString(),
4545
user: userEntity,
4646
relyingParty: relyingParty,
4747
publicKeyCredentialParameters: PublicKeyCredentialParameters.supported,
4848
timeout: config.timeout
4949
)
50-
let sessionData = SessionData(challenge: challenge.base64URLEncodedString(), userID: user.userID)
51-
52-
return (options, sessionData)
5350
}
5451

5552
/// Take response from authenticator and client and verify credential against the user's credentials and
5653
/// session data.
5754
/// - Parameters:
58-
/// - user: The user to verify against the authenticator response
59-
/// - sessionData: The data passed to the authenticator within the preceding registration options
55+
/// - challenge: The user to verify against the authenticator response. Base64 encoded.
6056
/// - credentialCreationData: The value returned from `navigator.credentials.create()`
6157
/// - requireUserVerification: Whether or not to require that the authenticator verified the user.
6258
/// - Returns: A new `Credential` with information about the authenticator and registration
6359
public func finishRegistration(
64-
for user: User,
65-
sessionData: SessionData,
60+
challenge: EncodedBase64,
6661
credentialCreationData: CredentialCreationResponse,
6762
requireUserVerification: Bool = false,
68-
supportedPublicKeyAlgorithms: [PublicKeyCredentialParameters] = PublicKeyCredentialParameters.supported
69-
) throws -> Credential {
70-
guard user.userID == sessionData.userID else { throw WebAuthnManagerError.userIDMismatch }
71-
63+
supportedPublicKeyAlgorithms: [PublicKeyCredentialParameters] = PublicKeyCredentialParameters.supported,
64+
confirmCredentialIDNotRegisteredYet: (String) async throws -> Bool
65+
) async throws -> Credential {
66+
// Step 3. - 16.
7267
let parsedData = try ParsedCredentialCreationResponse(from: credentialCreationData)
7368
try parsedData.verify(
74-
storedChallenge: sessionData.challenge,
69+
storedChallenge: String.base64URL(fromBase64: challenge),
7570
verifyUser: requireUserVerification,
7671
relyingPartyID: config.relyingPartyID,
7772
relyingPartyOrigin: config.relyingPartyOrigin
@@ -81,10 +76,18 @@ public struct WebAuthnManager {
8176
throw WebAuthnError.missingAttestedCredentialData
8277
}
8378

79+
// Step 17.
8480
let parsedPublicKeyData = try ParsedPublicKeyData(fromPublicKeyBytes: attestedData.publicKey)
8581
try parsedPublicKeyData.verify(supportedPublicKeyAlgorithms: supportedPublicKeyAlgorithms)
8682

87-
// Return a new credential record (based on step 25.)
83+
// TODO: Step 18. -> Verify client extensions
84+
85+
// Step 24.
86+
guard try await confirmCredentialIDNotRegisteredYet(parsedData.id) else {
87+
throw WebAuthnError.credentialIDAlreadyExists
88+
}
89+
90+
// Step 25.
8891
return Credential(
8992
type: parsedData.type,
9093
id: parsedData.id,

0 commit comments

Comments
 (0)