Skip to content

Commit

Permalink
Added feature tests for touch and sha512 to OATHSession. Also added c…
Browse files Browse the repository at this point in the history
…orresponding full stack tests.
  • Loading branch information
jensutbult committed Mar 7, 2024
1 parent 673c3eb commit bea194a
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 4 deletions.
38 changes: 38 additions & 0 deletions FullStackTests/Tests/OATHFullStackTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,44 @@ class OATHFullStackTests: XCTestCase {
}
}

func testSHA512Feature() throws {
runOATHTest(populated: false) { session in
let template = OATHSession.CredentialTemplate(type: .TOTP(), algorithm: .SHA512, secret: "abba2".base32DecodedData!, issuer: "SHA-512", name: "FeatureTest")
do {
try await session.addCredential(template: template)
guard let credential = try await session.listCredentials().first else { XCTFail("Failed adding SHA512 credential."); return }
XCTAssertEqual(credential.hashAlgorithm!, .SHA512)
XCTAssertEqual(String(data: credential.id, encoding: .utf8), template.identifier)
} catch {
guard let error = error as? SessionError, error == .notSupported else { XCTFail("Unexpected error: \(error)"); return }
print("⚠️ Skip testSHA512Feature()")
}
}
}

func testTouchFeature() throws {
runOATHTest(populated: false) { session in
do {
let touchTemplate = OATHSession.CredentialTemplate(type: .TOTP(), algorithm: .SHA256, secret: "abba2".base32DecodedData!, issuer: "Touch", name: "FeatureTest", requiresTouch: true)
try await session.addCredential(template: touchTemplate)
guard let touchCredential = try await session.calculateCodes().first else { XCTFail("Failed adding touch required credential."); return }
XCTAssertEqual(String(data: touchCredential.0.id, encoding: .utf8), touchTemplate.identifier)
XCTAssertTrue(touchCredential.0.requiresTouch)
XCTAssertNil(touchCredential.1)
try await session.deleteCredential(touchCredential.0)
let noTouchTemplate = OATHSession.CredentialTemplate(type: .TOTP(), algorithm: .SHA256, secret: "abba2".base32DecodedData!, issuer: "Touch", name: "FeatureTest", requiresTouch: false)
try await session.addCredential(template: noTouchTemplate)
guard let noTouchCredential = try await session.calculateCodes().first else { XCTFail("Failed adding no touch required credential."); return }
XCTAssertEqual(String(data: noTouchCredential.0.id, encoding: .utf8), noTouchTemplate.identifier)
XCTAssertNotNil(noTouchCredential.1)
XCTAssertFalse(noTouchCredential.0.requiresTouch)
} catch {
guard let error = error as? SessionError, error == .notSupported else { XCTFail("Unexpected error: \(error)"); return }
print("⚠️ Skip testTouchFeature()")
}
}
}

func testDeleteAccessKey() throws {
runOATHTest(password: "password") { session in
do {
Expand Down
10 changes: 8 additions & 2 deletions YubiKit/YubiKit/OATH/OATHSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,19 @@ public final actor OATHSession: Session, InternalSession {
/// The Credential ID (see ``OATHSession/CredentialTemplate/identifier``) must be unique to the YubiKey, or the
/// existing Credential with the same ID will be overwritten.
///
/// Setting requireTouch requires support for FEATURE_TOUCH, available on YubiKey 4.2 or later.
/// Using SHA-512 requires support for FEATURE_SHA512, available on YubiKey 4.3.1 or later.
/// Setting requireTouch requires support for touch, available on YubiKey 4.2 or later.
/// Using SHA-512 requires support for SHA-512, available on YubiKey 4.3.1 or later.
/// - Parameter template: The template describing the credential.
/// - Returns: The newly added credential.
@discardableResult
public func addCredential(template: CredentialTemplate) async throws -> Credential {
Logger.oath.debug("\(String(describing: self).lastComponent), \(#function)")
if template.algorithm == .SHA512 {
guard self.supports(OATHSessionFeature.sha512) else { throw SessionError.notSupported }
}
if template.requiresTouch {
guard self.supports(OATHSessionFeature.touch) else { throw SessionError.notSupported }
}
guard let connection = _connection else { throw SessionError.noConnection }
guard let nameData = template.identifier.data(using: .utf8) else { throw OATHSessionError.unexpectedData }
let nameTlv = TKBERTLVRecord(tag: 0x71, value: nameData)
Expand Down
8 changes: 6 additions & 2 deletions YubiKit/YubiKit/OATH/OATHSessionFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ import Foundation

public enum OATHSessionFeature: SessionFeature {

case rename
case rename, touch, sha512

public func isSupported(by version: Version) -> Bool {
switch self {
case .rename:
return version >= Version(withString: "5.3.0")!
case .touch:
return version >= Version(withString: "4.2.0")!
case .sha512:
return version >= Version(withString: "4.3.1")!
}
}
}

0 comments on commit bea194a

Please sign in to comment.