-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support loading RSAPSS public keys with parameters
Parameters are stripped and the key is treated as a regular public key.
- Loading branch information
1 parent
ffca28b
commit 2ec52ab
Showing
4 changed files
with
186 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// | ||
// SubjectPublicKeyInfo.swift | ||
// | ||
// | ||
// Created by Gautier Delorme on 24/09/2024. | ||
// | ||
|
||
import SwiftASN1 | ||
|
||
struct SubjectPublicKeyInfo: DERImplicitlyTaggable, Hashable { | ||
static var defaultIdentifier: ASN1Identifier { | ||
.sequence | ||
} | ||
|
||
var algorithmIdentifier: RFC5480AlgorithmIdentifier | ||
|
||
var key: ASN1BitString | ||
|
||
init(derEncoded rootNode: ASN1Node, withIdentifier identifier: ASN1Identifier) throws { | ||
// The SPKI block looks like this: | ||
// | ||
// SubjectPublicKeyInfo ::= SEQUENCE { | ||
// algorithm AlgorithmIdentifier, | ||
// subjectPublicKey BIT STRING | ||
// } | ||
self = try DER.sequence(rootNode, identifier: identifier) { nodes in | ||
let algorithmIdentifier = try RFC5480AlgorithmIdentifier(derEncoded: &nodes) | ||
let key = try ASN1BitString(derEncoded: &nodes) | ||
|
||
return SubjectPublicKeyInfo(algorithmIdentifier: algorithmIdentifier, key: key) | ||
} | ||
} | ||
|
||
private init(algorithmIdentifier: RFC5480AlgorithmIdentifier, key: ASN1BitString) { | ||
self.algorithmIdentifier = algorithmIdentifier | ||
self.key = key | ||
} | ||
|
||
internal init(algorithmIdentifier: RFC5480AlgorithmIdentifier, key: [UInt8]) { | ||
self.algorithmIdentifier = algorithmIdentifier | ||
self.key = ASN1BitString(bytes: key[...]) | ||
} | ||
|
||
func serialize(into coder: inout DER.Serializer, withIdentifier identifier: ASN1Identifier) throws { | ||
try coder.appendConstructedNode(identifier: identifier) { coder in | ||
try coder.serialize(self.algorithmIdentifier) | ||
try coder.serialize(self.key) | ||
} | ||
} | ||
} | ||
|
||
struct RFC5480AlgorithmIdentifier: DERImplicitlyTaggable, Hashable { | ||
static var defaultIdentifier: ASN1Identifier { | ||
.sequence | ||
} | ||
|
||
var algorithm: ASN1ObjectIdentifier | ||
|
||
var parameters: ASN1Any? | ||
|
||
init(algorithm: ASN1ObjectIdentifier, parameters: ASN1Any?) { | ||
self.algorithm = algorithm | ||
self.parameters = parameters | ||
} | ||
|
||
init(derEncoded rootNode: ASN1Node, withIdentifier identifier: ASN1Identifier) throws { | ||
// The AlgorithmIdentifier block looks like this. | ||
// | ||
// AlgorithmIdentifier ::= SEQUENCE { | ||
// algorithm OBJECT IDENTIFIER, | ||
// parameters ANY DEFINED BY algorithm OPTIONAL | ||
// } | ||
// | ||
// ECParameters ::= CHOICE { | ||
// namedCurve OBJECT IDENTIFIER | ||
// -- implicitCurve NULL | ||
// -- specifiedCurve SpecifiedECDomain | ||
// } | ||
// | ||
// We don't bother with helpers: we just try to decode it directly. | ||
self = try DER.sequence(rootNode, identifier: identifier) { nodes in | ||
let algorithmOID = try ASN1ObjectIdentifier(derEncoded: &nodes) | ||
|
||
let parameters = nodes.next().map { ASN1Any(derEncoded: $0) } | ||
|
||
return .init(algorithm: algorithmOID, parameters: parameters) | ||
} | ||
} | ||
|
||
func serialize(into coder: inout DER.Serializer, withIdentifier identifier: ASN1Identifier) throws { | ||
try coder.appendConstructedNode(identifier: identifier) { coder in | ||
try coder.serialize(self.algorithm) | ||
if let parameters = self.parameters { | ||
try coder.serialize(parameters) | ||
} | ||
} | ||
} | ||
} | ||
|
||
extension SubjectPublicKeyInfo { | ||
static func stripRsaPssParameters(derEncoded: [UInt8]) throws -> [UInt8] { | ||
guard var spki = try? SubjectPublicKeyInfo(derEncoded: derEncoded) else { | ||
// If it's not a SPKI then it can't be a PSS key so we just return it. | ||
return derEncoded | ||
} | ||
|
||
if spki.algorithmIdentifier.algorithm == .AlgorithmIdentifier.rsaPSS { | ||
spki.algorithmIdentifier.parameters = try ASN1Any(erasing: ASN1Null()) | ||
} | ||
|
||
var serializer = DER.Serializer() | ||
try serializer.serialize(spki) | ||
|
||
return serializer.serializedBytes | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters