Skip to content

Commit

Permalink
Add extKeyUsage convenience mutators to builders
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb committed Jan 11, 2020
1 parent eeba172 commit 26e984b
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 11 deletions.
8 changes: 6 additions & 2 deletions Sources/ShieldX509/CertificateBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ public extension Certificate {
var extensions = self.extensions
if let keyUsage = keyUsage {
extensions = extensions ?? Extensions()
extensions!.remove(KeyUsage.self)
try extensions!.append(value: keyUsage)
try extensions!.replace(value: keyUsage)
}

let subjectPublicKeyInfo = SubjectPublicKeyInfo(algorithm: algorithm, subjectPublicKey: publicKey)
Expand All @@ -156,6 +155,11 @@ public extension Certificate {
notBefore: notBefore, notAfter: notAfter, extensions: extensions)
}

public func extendedKeyUsage(keyPurposes: Set<OID>, isCritical: Bool) throws -> Builder {

return try addExtension(value: ExtKeyUsage(keyPurposes: keyPurposes), isCritical: isCritical)
}

public func basicConstraints(ca: Bool, pathLength: Int? = nil) throws -> Builder {

return try addExtension(value: BasicConstraints(ca: ca, pathLenConstraint: pathLength))
Expand Down
31 changes: 23 additions & 8 deletions Sources/ShieldX509/CertificationRequestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//

import Foundation
import PotentASN1


public extension CertificationRequest {
Expand Down Expand Up @@ -70,19 +71,33 @@ public extension CertificationRequest {
algorithm: AlgorithmIdentifier,
usage keyUsage: KeyUsage? = nil) throws -> Builder {

var attributes = self.attributes
if let keyUsage = keyUsage {
attributes = attributes ?? CRAttributes()
var extensions = try attributes!.first(Extensions.self) ?? Extensions()
extensions.remove(KeyUsage.self)
try extensions.append(value: keyUsage)
var builder = self

attributes!.remove(Extensions.self)
attributes!.append(singleValued: extensions)
if let keyUsage = keyUsage {
builder = try builder.extension(Extension(value: keyUsage))
}

let subjectPKInfo = SubjectPublicKeyInfo(algorithm: algorithm, subjectPublicKey: publicKey)

return Builder(subject: builder.subject, subjectPKInfo: subjectPKInfo, attributes: builder.attributes)
}

public func extendedKeyUsage(keyPurposes: Set<OID>, isCritical: Bool) throws -> Builder {

let extKeyUsage = ExtKeyUsage(keyPurposes: keyPurposes)

return try `extension`(Extension(value: extKeyUsage, critical: isCritical))
}

public func `extension`(_ extension: Extension) throws -> Builder {

var attributes = self.attributes ?? CRAttributes()
var extensions = try attributes.first(Extensions.self) ?? Extensions()

extensions.replace(`extension`)

attributes.replace(singleValued: extensions)

return Builder(subject: subject, subjectPKInfo: subjectPKInfo, attributes: attributes)
}

Expand Down
59 changes: 59 additions & 0 deletions Sources/ShieldX509/ExtensionExtKeyUsage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// ExtensionKeyUsage.swift
// Shield
//
// Copyright © 2019 Outfox, inc.
//
//
// Distributed under the MIT License, See LICENSE for details.
//

import Foundation
import PotentASN1
import ShieldOID


public struct ExtKeyUsage: Equatable, Hashable, Codable, ExtensionValue {

public static var extensionID = iso_itu.ds.certificateExtension.extKeyUsage.oid
public static var asn1Schema = Schemas.extKeyUsageExtension

public let keyPurposes: Set<OID>

public init(keyPurposes: Set<OID>) {
self.keyPurposes = keyPurposes
}
}



// MARK: Schemas

public extension Schemas {

static let extKeyUsageExtension: Schema = .sequenceOf(.objectIdentifier())

}


// MARK: KeyUsage Conformances

extension ExtKeyUsage {

public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var keyPurposes = Set<OID>()
for _ in 0 ..< (container.count ?? 0) {
keyPurposes.insert(try container.decode(OID.self))
}
self.keyPurposes = keyPurposes
}

public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for keyPurpose in keyPurposes {
try container.encode(keyPurpose)
}
}

}
7 changes: 6 additions & 1 deletion Tests/CertificateBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import BigInt
import PotentASN1
import ShieldOID
@testable import Shield
import XCTest

Expand Down Expand Up @@ -122,6 +123,8 @@ class CertificateBuilderTests: XCTestCase {
.subject(name: subject, uniqueID: subjectID)
.subjectAlternativeNames(names: .dnsName("github.com/outfoxx/Shield"))
.publicKey(keyPair: keyPair)
.extendedKeyUsage(keyPurposes: [iso.org.dod.internet.security.mechanisms.pkix.kp.serverAuth.oid],
isCritical: false)
.issuer(name: issuer, uniqueID: issuerID)
.valid(for: 86400 * 365)
.build(signingKey: keyPair.privateKey, digestAlgorithm: .sha256)
Expand Down Expand Up @@ -223,7 +226,9 @@ class CertificateBuilderTests: XCTestCase {
try CertificationRequest.Builder()
.subject(name: NameBuilder().add("Shield Subject", forTypeName: "CN").name)
.alternativeNames(names: altNames)
.publicKey(keyPair: keyPair)
.publicKey(keyPair: keyPair, usage: [.dataEncipherment])
.extendedKeyUsage(keyPurposes: [iso.org.dod.internet.security.mechanisms.pkix.kp.serverAuth.oid],
isCritical: false)
.build(signingKey: keyPair.privateKey, digestAlgorithm: .sha256)
.encoded()

Expand Down

0 comments on commit 26e984b

Please sign in to comment.