Skip to content

Commit 402e06f

Browse files
committed
add beginRegistration method
1 parent f752685 commit 402e06f

File tree

9 files changed

+110
-4
lines changed

9 files changed

+110
-4
lines changed

Sources/WebAuthn/Credential.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Crypto
1818
public struct Credential {
1919
/// base64 encoded String of the credential ID bytes
2020
public let credentialID: String
21-
21+
2222
/// The public key for this certificate
2323
public let publicKey: P256.Signing.PublicKey
2424
}

Sources/WebAuthn/Entities.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// From §5.4.1 (https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity).
2+
/// `PublicKeyCredentialEntity`` describes a user account, or a WebAuthn Relying Party,
3+
/// with which a public key credential is associated.
4+
public protocol PublicKeyCredentialEntity: Codable {
5+
var name: String { get }
6+
}
7+
8+
/// From §5.4.2 (https://www.w3.org/TR/webauthn/#sctn-rp-credential-params).
9+
/// The PublicKeyCredentialRpEntity dictionary is used to supply additional Relying Party attributes when creating a
10+
/// new credential.
11+
public struct PublicKeyCredentialRpEntity: PublicKeyCredentialEntity, Codable {
12+
public let name: String
13+
14+
public let id: String
15+
}
16+
17+
/// From §5.4.3 (https://www.w3.org/TR/webauthn/#dictionary-user-credential-params)
18+
/// The PublicKeyCredentialUserEntity dictionary is used to supply additional user account attributes when creating a
19+
/// new credential.
20+
public struct PublicKeyCredentialUserEntity: PublicKeyCredentialEntity, Codable {
21+
public let name: String
22+
23+
public let id: String
24+
public let displayName: String
25+
}

Sources/WebAuthn/Helpers/WebAuthn+generateChallenge.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import Logging
33

4-
extension WebAuthn {
4+
extension WebAuthnManager {
55
struct ChallengeGeneratorError: Error {}
66
/// Generate a suitably random value to be used as an attestation or assertion challenge
77
/// - Throws: An error if something went wrong while generating random byte
@@ -17,12 +17,18 @@ extension WebAuthn {
1717
extension Array where Element == UInt8 {
1818
/// Encodes an array of bytes into a base64url-encoded string
1919
/// - Returns: A base64url-encoded string
20-
public func base64URLEncode() -> String {
20+
public func base64URLEncodedString() -> String {
2121
let base64String = Data(bytes: self, count: self.count).base64EncodedString()
2222
return base64String.replacingOccurrences(of: "+", with: "-")
2323
.replacingOccurrences(of: "/", with: "_")
2424
.replacingOccurrences(of: "=", with: "")
2525
}
26+
27+
/// Encodes an array of bytes into a base64 string
28+
/// - Returns: A base64-encoded string
29+
public func base64EncodedString() -> String {
30+
return Data(bytes: self, count: self.count).base64EncodedString()
31+
}
2632
}
2733

2834
extension String {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// See §5.4. https://www.w3.org/TR/webauthn/#dictionary-makecredentialoptions
2+
/// Contains a PublicKeyCredentialCreationOptions object specifying the desired attributes of the
3+
/// to-be-created public key credential.
4+
public struct PublicKeyCredentialCreationOptions: Codable {
5+
public let challenge: String
6+
public let user: PublicKeyCredentialUserEntity
7+
public let relyingParty: PublicKeyCredentialRpEntity
8+
}

Sources/WebAuthn/SessionData.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// SessionData is the data that should be stored by the Relying Party for the duration of the web authentication
2+
/// ceremony
3+
public struct SessionData {
4+
public let challenge: String
5+
public let userID: String
6+
}

Sources/WebAuthn/User.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public struct User {
2+
public let id: String
3+
public let name: String
4+
public let displayName: String
5+
6+
public init(id: String, name: String, displayName: String) {
7+
self.id = id
8+
self.name = name
9+
self.displayName = displayName
10+
}
11+
}

Sources/WebAuthn/WebAuthnConfig.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public struct Config {
2+
public let relyingPartyDisplayName: String
3+
public let relyingPartyID: String
4+
5+
public init(relyingPartyDisplayName: String, relyingPartyID: String) {
6+
self.relyingPartyDisplayName = relyingPartyDisplayName
7+
self.relyingPartyID = relyingPartyID
8+
}
9+
}
10+
11+
public var config: Config!

Sources/WebAuthn/WebAuthn.swift renamed to Sources/WebAuthn/WebAuthnManager.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,24 @@ import Crypto
1717
import Logging
1818
import Foundation
1919

20-
public enum WebAuthn {
20+
public enum WebAuthnManager {
21+
/// Generate a new set of registration data to be sent to the client and authenticator.
22+
public static func beginRegistration(user: User) throws -> (PublicKeyCredentialCreationOptions, SessionData) {
23+
let userEntity = PublicKeyCredentialUserEntity(name: user.name, id: user.id, displayName: user.displayName)
24+
let relyingParty = PublicKeyCredentialRpEntity(name: config.relyingPartyDisplayName, id: config.relyingPartyID)
25+
26+
let challenge = try generateChallenge()
27+
28+
let options = PublicKeyCredentialCreationOptions(
29+
challenge: challenge.base64EncodedString(),
30+
user: userEntity,
31+
relyingParty: relyingParty
32+
)
33+
let sessionData = SessionData(challenge: challenge.base64URLEncodedString(), userID: user.id)
34+
35+
return (options, sessionData)
36+
}
37+
2138
/// Verify that the user has legitimately completed the login process
2239
///
2340
/// - Parameters:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import XCTest
2+
@testable import WebAuthn
3+
4+
final class HelpersTests: XCTestCase {
5+
func testGenerateChallengeReturnsRandomBytes() throws {
6+
let challenge1 = try WebAuthnManager.generateChallenge()
7+
let challenge2 = try WebAuthnManager.generateChallenge()
8+
9+
XCTAssertNotEqual(challenge1, challenge2)
10+
}
11+
12+
func testBase64URLEncodeReturnsCorrectString() {
13+
let input: [UInt8] = [1, 0, 1, 0, 1, 1]
14+
let expectedBase64 = Data(bytes: input, count: input.count).base64EncodedString()
15+
16+
let base64URLEncoded = input.base64URLEncodedString()
17+
let base64Encoded = base64URLEncoded.replacingOccurrences(of: "-", with: "+")
18+
.replacingOccurrences(of: "_", with: "/")
19+
20+
XCTAssertEqual(expectedBase64, base64Encoded)
21+
}
22+
}

0 commit comments

Comments
 (0)