Skip to content
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

extras: Add APIs for RSA Blind Signatures #232

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

simonjbeaumont
Copy link
Contributor

@simonjbeaumont simonjbeaumont commented May 21, 2024

Motivation

RFC 9474 defines the RSA Blind Signatures protocol1, which are a useful building block of privacy-preserving schemes.

Modifications

This PR adds the following public API surface to implement the RSA Blind Signatures protocol:

public struct _RSA.BlindSigning.Parameters<H: HashFunction> {}

extension _RSA.BlindSigning.Parameters where H == SHA384 {
    public static let RSABSSA_SHA384_PSS_Randomized: Self<SHA384>
    public static let RSABSSA_SHA384_PSS_Deterministic: Self<SHA384>
    public static let RSABSSA_SHA384_PSSZERO_Randomized: Self<SHA384>
    public static let RSABSSA_SHA384_PSSZERO_Deterministic: Self<SHA384>
}

public struct _RSA.BlindSigning.PrivateKey {
    public typealias Parameters = _RSA.BlindSigning.Parameters<H>

    // ... similar initializers as other protocol-segreated key types, but taking parameters parameter ...

    // ... same properties as other protocol-segregated key types ...

    public func blindSignature<D: DataProtocol>(for message: D) throws -> _RSA.BlindSigning.BlindSignature
}

public struct _RSA.BlindSigning.PublicKey {
    public typealias Parameters = _RSA.BlindSigning.Parameters<H>

    // ... similar initializers as other protocol-segreated key types, but taking parameters parameter ...

    // ... same properties as other protocol-segregated key types ...

    public func prepare<D: DataProtocol>(_ message: D) -> _RSA.BlindSigning.PreparedMessage

    public func blind(_ message: _RSA.BlindSigning.PreparedMessage) throws -> (blindedMessage: Data, blindInverse: _RSA.BlindSigning.BlindInverse)

    public func finalize(_ signature: _RSA.BlindSigning.BlindSignature, for message: _RSA.BlindSigning.PreparedMessage,
 blindInverse: _RSA.BlindSigning.BlindInverse) throws -> _RSA.Signing.RSASignature

    public func isValidSignature(_ signature: _RSA.Signing.RSASignature, for message: _RSA.BlindSigning.PreparedMessage) -> Bool
}

It also adds tests using the test vectors from the RFC, where possible. That is, for each of the operations except for blind, which we don't have the BoringSSL APIs that would allow us to inject the fixed salt value from the test vectors.

While it's possible to implement the server-side operations using Security framework, it does not expose the APIs we would need to implement the client-side operations so, because the goal is to also provide the client-side operations in a subsequent PR, the implementation uses BoringSSL on all platforms.

In order to construct the RSA keys from the test vector parameters, some BoringSSL helpers were added.

The implementation has been done without the need for ArbitraryPrecisionInteger, which currently exists as an internal type in the Crypto module. The API has been designed to not preclude its use at a future time, should we have it available, e.g. the BlindInverse type is entirely opaque and its underlying representation could be changed as an implementation detail.

Result

New API in the _CryptoExtras module for the the RSA Blind Signatures protocol as defined in RFC 9474, with support for all named variants: for the RSABSSA_SHA384_PSS_Randomized, RSABSSA_SHA384_PSS_Deterministic, RSABSSA_SHA384_PSSZERO_Randomized, and RSABSSA_SHA384_PSSZERO_Deterministic.

Footnotes

  1. https://datatracker.ietf.org/doc/rfc9474/

@simonjbeaumont simonjbeaumont marked this pull request as ready for review May 21, 2024 12:52
@Lukasa Lukasa added the 🔼 needs-minor-version-bump For PRs that when merged cause a bump of the minor version, ie. 1.x.0 -> 1.(x+1).0 label May 21, 2024
Sources/_CryptoExtras/Util/BoringSSLHelpers.swift Outdated Show resolved Hide resolved
Tests/_CryptoExtrasTests/TestRSABlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Outdated Show resolved Hide resolved
) == 1 else {
throw CryptoKitError.internalBoringSSLError()
}
precondition(outputCount == signatureByteCount)
Copy link
Member

Choose a reason for hiding this comment

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

Did you test this on enough key sizes that it's always true? (eg. if first bytes are 0, they are not getting trimmed)

Just want to make sure we don't crash if we have an oddly formatted private key generated some day.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah. Let me double check on this, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looked again at this and we compute signatureByteCount using BoringSSL RSA_size which returns the size of the modulus in bytes (as opposed to the key size). I also confirmed that BoringSSL RSA_sign_raw allocates a buffer of that size and sets out_len to the same.

@simonjbeaumont simonjbeaumont changed the title Server-side APIs for RSA Blind Signatures extras: Add APIs for RSA Blind Signatures Jun 5, 2024
@simonjbeaumont
Copy link
Contributor Author

@Lukasa this is ready for another pass when you have time.

Sources/_CryptoExtras/Util/RandomBytes.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA+BlindSigning.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Outdated Show resolved Hide resolved
Sources/_CryptoExtras/RSA/RSA_boring.swift Outdated Show resolved Hide resolved
@simonjbeaumont
Copy link
Contributor Author

@Lukasa OK, thanks for the latest round of feedback. I've addressed all that now, so it's ready for another pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔼 needs-minor-version-bump For PRs that when merged cause a bump of the minor version, ie. 1.x.0 -> 1.(x+1).0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants