Skip to content

RSA support and modularity add-ons #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed

RSA support and modularity add-ons #87

wants to merge 5 commits into from

Conversation

dscreve
Copy link
Contributor

@dscreve dscreve commented Jan 25, 2025

  • Make ChallengeGenerator more flexible and overridable
  • Add custom challenge for authentication and registration
  • Implement Codable in most object Add public init on most objects
  • Implements RSA (required for Windows Hello)
  • Add OpenAPI support on PublicKeyCredentialRequestOptions and PublicKeyCredentialCreationOptions

… challenge for authentication and registration)

Implement Codable in most object
Add public init on most object
Implements RSA
Copy link
Collaborator

@dimitribouniol dimitribouniol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR! It seems like there are four main things this introduces, and I'd like to propose you split out some of them to keep changes clear and to the point:

  • RSA support: Please keep this PR focussed on RSA support, and add appropriate tests — what's here so far looks good so far!
  • Public inits, mutable properties, and full Codable support: Please split this out into it's own PR, as it seems to be quite inconsistently applied, and could benefit from a more careful review to make sure we get everything properly.
  • Customizable Challenges: I'm not sure there is good motivation to customize this, but either way, not sure RSA support is blocked by it, so no need to block it on reaching consensus here.
  • VaporOpenAPI support: this feels like it belongs in a completely separate package. Vapor Community has many such packages, and it may find a more appropriate home there.

@@ -36,7 +37,8 @@ let package = Package(
.product(name: "Crypto", package: "swift-crypto"),
.product(name: "_CryptoExtras", package: "swift-crypto"),
.product(name: "Logging", package: "swift-log"),
],
.product(name:"VaporToOpenAPI",package:"VaporToOpenAPI"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel appropriate to add to this package as it isn't guaranteed to be used with vapor or OpenAPI. As an alternative to removing it completely, could this instead live in a separate package that augments swift-webauthn for those who want this functionality.

Comment on lines +48 to +56
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(id, forKey: .id)
try container.encode(rawID.base64URLEncodedString(), forKey: .rawID)
try container.encode(response, forKey: .response)
try container.encodeIfPresent(authenticatorAttachment, forKey: .authenticatorAttachment)
try container.encode(type, forKey: .type)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: formatting

Comment on lines +62 to +70
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(clientDataJSON.base64URLEncodedString(), forKey: .clientDataJSON)
try container.encode(authenticatorData.base64URLEncodedString(), forKey: .authenticatorData)
try container.encode(signature.base64URLEncodedString(), forKey: .signature)
try container.encodeIfPresent(userHandle?.base64URLEncodedString(),forKey: .userHandle)
try container.encodeIfPresent(attestationObject?.base64URLEncodedString(),forKey: .attestationObject)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: formatting

Comment on lines 68 to 74
public init(_ src : PublicKeyCredentialRequestOptions) {
self.challenge=src.challenge
self.timeout=src.timeout
self.relyingPartyID=src.relyingPartyID
self.allowCredentials=src.allowCredentials
self.userVerification = src.userVerification
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no point to this, you can just copy it since it's a struct.

Comment on lines +76 to +77
public init(challenge: [UInt8],user: PublicKeyCredentialUserEntity,relyingParty: PublicKeyCredentialRelyingPartyEntity,publicKeyCredentialParameters: [PublicKeyCredentialParameters],
timeout: Duration?,attestation: AttestationConveyancePreference) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: formatting

Suggested change
public init(challenge: [UInt8],user: PublicKeyCredentialUserEntity,relyingParty: PublicKeyCredentialRelyingPartyEntity,publicKeyCredentialParameters: [PublicKeyCredentialParameters],
timeout: Duration?,attestation: AttestationConveyancePreference) {
public init(
challenge: [UInt8],
user: PublicKeyCredentialUserEntity,relyingParty: PublicKeyCredentialRelyingPartyEntity,
publicKeyCredentialParameters: [PublicKeyCredentialParameters],
timeout: Duration?,
attestation: AttestationConveyancePreference
) {

Comment on lines 189 to 208
//throw WebAuthnError.unsupported
let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature)

var rsaPadding: _RSA.Signing.Padding
switch algorithm {
case .algRS1, .algRS256, .algRS384, .algRS512:
rsaPadding = .insecurePKCS1v1_5
case .algPS256, .algPS384, .algPS512:
rsaPadding = .PSS
default:
throw WebAuthnError.unsupportedCOSEAlgorithmForRSAPublicKey
}

guard try _RSA.Signing.PublicKey(derRepresentation: rawRepresentation).isValidSignature(
rsaSignature,
for: data,
padding: rsaPadding
) else {
throw WebAuthnError.invalidSignature
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add tests for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've written the tests, but unfortunately, CryptoKit does not allow the creation of 256 bit private key...So, tests cannot be performed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you are referencing the right key size? https://www.rfc-editor.org/rfc/rfc8812.html
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right : I inverted key size and hash.
I fix it.

Comment on lines -14 to +23
package struct ChallengeGenerator: Sendable {
var generate: @Sendable () -> [UInt8]
public protocol ChallengeGenerator : Sendable {
func generate() -> [UInt8]
}

package static var live: Self {
.init(generate: { [UInt8].random(count: 32) })
public struct DefaultChallengeGenerator: Sendable, ChallengeGenerator {
public func generate() -> [UInt8] {
return [UInt8].random(count: 32)
}

public static let live = DefaultChallengeGenerator()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I see the motivation for changing this.

@dscreve
Copy link
Contributor Author

dscreve commented Jan 26, 2025 via email

@dscreve
Copy link
Contributor Author

dscreve commented Jan 27, 2025

Actually, RSA cannot be tested because CryptoKit does not allow creation of RSA key with size lower than 2048 bits...while WebAuthn use 325,384 and 512 bits.

@dscreve dscreve closed this Jan 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants