Skip to content

Commit

Permalink
Fix Swift port for Xcode 7b5, tweak API
Browse files Browse the repository at this point in the history
Use failing init for key generator/verifier
Prune error types
Fix interfacing with C API so that Clang doesn't die during build
Add verifier to test target
Fix typo in comment
  • Loading branch information
glebd committed Aug 14, 2015
1 parent b96a614 commit d38dd66
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 217 deletions.
2 changes: 2 additions & 0 deletions swift/CocoaFob.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
C75B81E01B57421A003D4BCD /* CocoaFobStringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75B81DF1B57421A003D4BCD /* CocoaFobStringExt.swift */; };
C75B81E21B574222003D4BCD /* CocoaFobLicGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75B81E11B574222003D4BCD /* CocoaFobLicGenerator.swift */; };
C77D712A1B5496F00019F670 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77D71291B5496F00019F670 /* main.swift */; };
C782622C1B7D8C80001C41CE /* CocoaFobLicVerifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75B81D91B5741D4003D4BCD /* CocoaFobLicVerifier.swift */; };
C7C398631B55F95200DCF644 /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C398601B55F95200DCF644 /* CommandLine.swift */; };
C7C398641B55F95200DCF644 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C398611B55F95200DCF644 /* Option.swift */; };
C7C398651B55F95200DCF644 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C398621B55F95200DCF644 /* StringExtensions.swift */; };
Expand Down Expand Up @@ -328,6 +329,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C782622C1B7D8C80001C41CE /* CocoaFobLicVerifier.swift in Sources */,
C739DCD21B48DFA10074D8F2 /* CocoaFobTests.swift in Sources */,
C7101B751B52C66D00A71BA8 /* CocoaFobStringExt.swift in Sources */,
C739DCDE1B48E0240074D8F2 /* CocoaFobLicGenerator.swift in Sources */,
Expand Down
28 changes: 2 additions & 26 deletions swift/CocoaFob/CocoaFobError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,8 @@ import Foundation

/**
Custom error type:
- InvalidKey(OSStatus): The supplied key is invalid; use `security error <OSStatus>` to get the message
- DecodeError: The supplied key could not be decoded
- InvalidName: Invalid user name supplied
- ErrorCreatingSignerTransform: Unable to create cryptographic signing transform
- ErrorConfiguringSignerTransform: Unable to configure signer transform
- ErrorCreatingEncoderTransform: Unable to create Base32 encoder transform
- ErrorCreatingDecoderTransform: Unable to create Base32 decoder transform
- ErrorConfiguringDecoderTransform: Unable to configure Base32 decoder transform
- ErrorCreatingGroupTransform: Unable to create group transform
- ErrorGeneratingRegKey: Unable to generate registration key
- ErrorCreatingVerifierTransform: Unable to create verifier transform
- ErrorConfiguringVerifierTransform: Unable to configure verifier transform
- VerificationError: Error verifying registration key
- Error: Unspecified error
*/
enum CocoaFobError: ErrorType {
case InvalidKey(OSStatus)
case DecodeError
case InvalidInput
case ErrorCreatingSignerTransform
case ErrorConfiguringSignerTransform
case ErrorCreatingEncoderTransform
case ErrorCreatingDecoderTransform
case ErrorConfiguringDecoderTransform
case ErrorCreatingGroupTransform
case ErrorGeneratingRegKey
case ErrorCreatingVerifierTransform
case ErrorConfiguringVerifierTransform
case VerificationError
case Error
}
80 changes: 44 additions & 36 deletions swift/CocoaFob/CocoaFobLicGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,38 @@ public struct CocoaFobLicGenerator {

- parameter privateKeyPEM: String containing PEM representation of the private key
*/
public init(privateKeyPEM: String) throws {
var password = Unmanaged.passUnretained(NSString(string: "") as AnyObject)
var emptyString = "" as NSString
public init?(privateKeyPEM: String) {
let emptyString = "" as NSString
let password = Unmanaged.passUnretained(emptyString as AnyObject)
var params = SecItemImportExportKeyParameters(
version: UInt32(bitPattern: SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION),
flags: SecKeyImportExportFlags.ImportOnlyOne,
passphrase: password,
alertTitle: Unmanaged.passUnretained(NSString(string: "")),
alertPrompt: Unmanaged.passUnretained(NSString(string: "")),
alertTitle: Unmanaged.passUnretained(emptyString),
alertPrompt: Unmanaged.passUnretained(emptyString),
accessRef: nil,
keyUsage: nil,
keyAttributes: nil)
var keyFormat = SecExternalFormat.FormatPEMSequence
var keyType = SecExternalItemType.ItemTypePrivateKey
if let keyData = privateKeyPEM.dataUsingEncoding(NSUTF8StringEncoding) {
let keyBytes = unsafeBitCast(keyData.bytes, UnsafePointer<UInt8>.self)
let keyDataCF = CFDataCreate(nil, keyBytes, keyData.length)!
var importArray: CFArray? = nil
let osStatus = withUnsafeMutablePointer(&importArray) { importArrayPtr in
SecItemImport(keyData, nil, &keyFormat, &keyType, 0, &params, nil, importArrayPtr)
let osStatus = withUnsafeMutablePointers(&keyFormat, &keyType) { (pKeyFormat, pKeyType) -> OSStatus in
SecItemImport(keyDataCF, nil, pKeyFormat, pKeyType, SecItemImportExportFlags(rawValue: 0), &params, nil, &importArray)
}
if osStatus != errSecSuccess {
throw CocoaFobError.InvalidKey(osStatus)
if osStatus != errSecSuccess || importArray == nil {
return nil
}
if let items = importArray as? NSArray where items.count >= 1 {
let items = importArray! as NSArray
if items.count >= 1 {
self.privKey = items[0] as! SecKeyRef
} else {
throw CocoaFobError.InvalidKey(0)
return nil
}
} else {
throw CocoaFobError.InvalidKey(0)
return nil
}
}

Expand All @@ -63,48 +66,53 @@ public struct CocoaFobLicGenerator {
- returns: Registration key
*/
public func generate(name: String) throws -> String {
guard name != "" else { throw CocoaFobError.InvalidInput }
let nameData = try getNameData(name)
let signer = try getSigner(nameData)
let encoder = try getEncoder()
if let group = try connectTransforms(signer, encoder: encoder) {
let regData = try cfTry(CocoaFobError.ErrorGeneratingRegKey) { return SecTransformExecute(group, $0) }
guard name != "" else { throw CocoaFobError.Error }
if let nameData = getNameData(name), signer = getSigner(nameData), encoder = getEncoder(), group = connectTransforms(signer, encoder: encoder) {
let regData = try cfTry(CocoaFobError.Error) { return SecTransformExecute(group, $0) }
if let reg = NSString(data: regData as! NSData, encoding: NSUTF8StringEncoding) {
return String(reg).cocoaFobToReadableKey()
} else {
throw CocoaFobError.ErrorGeneratingRegKey
throw CocoaFobError.Error
}
}
throw CocoaFobError.Error
}

// MARK: - Utility functions

private func connectTransforms(signer: SecTransform, encoder: SecTransform) throws -> SecGroupTransform? {
let groupTransform = try getGroupTransform()
return SecTransformConnectTransforms(signer, kSecTransformOutputAttributeName, encoder, kSecTransformInputAttributeName, groupTransform, nil)
private func connectTransforms(signer: SecTransform, encoder: SecTransform) -> SecGroupTransform? {
if let groupTransform = getGroupTransform() {
return SecTransformConnectTransforms(signer, kSecTransformOutputAttributeName, encoder, kSecTransformInputAttributeName, groupTransform, nil)
}
return nil
}

private func getGroupTransform() throws -> SecGroupTransform {
private func getGroupTransform() -> SecGroupTransform? {
return SecTransformCreateGroupTransform()
}

func getNameData(name: String) throws -> NSData {
if let nameData = name.dataUsingEncoding(NSUTF8StringEncoding) {
return nameData
}
throw CocoaFobError.InvalidInput
func getNameData(name: String) -> NSData? {
return name.dataUsingEncoding(NSUTF8StringEncoding)
}

func getSigner(nameData: NSData) throws -> SecTransform {
let signer = try cfTry(.ErrorCreatingSignerTransform) { return SecSignTransformCreate(self.privKey, $0) }
try cfTry(.ErrorConfiguringSignerTransform) { return SecTransformSetAttribute(signer, kSecTransformInputAttributeName, nameData, $0) }
try cfTry(.ErrorConfiguringSignerTransform) { return SecTransformSetAttribute(signer, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
return signer
func getSigner(nameData: NSData) -> SecTransform? {
do {
let signer = try cfTry(.Error) { return SecSignTransformCreate(self.privKey, $0) }
try cfTry(.Error) { return SecTransformSetAttribute(signer, kSecTransformInputAttributeName, nameData, $0) }
try cfTry(.Error) { return SecTransformSetAttribute(signer, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
return signer
} catch {
return nil
}
}

private func getEncoder() throws -> SecTransform {
let encoder = try cfTry(.ErrorCreatingEncoderTransform) { return SecEncodeTransformCreate(kSecBase32Encoding, $0) }
return encoder
private func getEncoder() -> SecTransform? {
do {
let encoder = try cfTry(.Error) { return SecEncodeTransformCreate(kSecBase32Encoding, $0) }
return encoder
} catch {
return nil
}
}

}
43 changes: 23 additions & 20 deletions swift/CocoaFob/CocoaFobLicVerifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,43 @@ public struct CocoaFobLicVerifier {

- parameter publicKeyPEM: String containing PEM representation of the public key
*/
public init(publicKeyPEM: String) throws {
var password = Unmanaged.passUnretained(NSString(string: "") as AnyObject)
var emptyString = "" as NSString
public init?(publicKeyPEM: String) {
let emptyString = "" as NSString
let password = Unmanaged.passUnretained(emptyString as AnyObject)
var params = SecItemImportExportKeyParameters(
version: UInt32(bitPattern: SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION),
flags: SecKeyImportExportFlags.ImportOnlyOne,
passphrase: password,
alertTitle: Unmanaged.passUnretained(NSString(string: "")),
alertPrompt: Unmanaged.passUnretained(NSString(string: "")),
alertTitle: Unmanaged.passUnretained(emptyString),
alertPrompt: Unmanaged.passUnretained(emptyString),
accessRef: nil,
keyUsage: nil,
keyAttributes: nil)
var keyFormat = SecExternalFormat.FormatPEMSequence
var keyType = SecExternalItemType.ItemTypePublicKey
if let keyData = publicKeyPEM.dataUsingEncoding(NSUTF8StringEncoding) {
let keyBytes = unsafeBitCast(keyData.bytes, UnsafePointer<UInt8>.self)
let keyDataCF = CFDataCreate(nil, keyBytes, keyData.length)!
var importArray: CFArray? = nil
let osStatus = withUnsafeMutablePointer(importArray) { importArrayPtr in
SecItemImport(keyData, nil, &keyFormat, &keyType, 0, &params, nil, importArrayPtr)
let osStatus = withUnsafeMutablePointers(&keyFormat, &keyType) { (pKeyFormat, pKeyType) -> OSStatus in
SecItemImport(keyDataCF, nil, pKeyFormat, pKeyType, SecItemImportExportFlags(rawValue: 0), &params, nil, &importArray)
}
if osStatus != errSecSuccess {
throw CocoaFobError.InvalidKey(osStatus)
if osStatus != errSecSuccess || importArray == nil {
return nil
}
if let items = importArray as? NSArray where items.count >= 1 {
let items = importArray! as NSArray
if items.count >= 1 {
self.pubKey = items[0] as! SecKeyRef
} else {
throw CocoaFobError.InvalidKey(0)
return nil
}
} else {
throw CocoaFobError.InvalidKey(0)
return nil
}
}

/**
Verifies registration key against registered name. Doesn't throw since you are mst likely not interested in the reason registration verification failed.
Verifies registration key against registered name. Doesn't throw since you are most likely not interested in the reason registration verification failed.

- parameter regKey: Registration key string
- parameter name: Registered name string
Expand All @@ -65,9 +68,9 @@ public struct CocoaFobLicVerifier {
do {
if let keyData = regKey.cocoaFobFromReadableKey().dataUsingEncoding(NSUTF8StringEncoding), nameData = name.dataUsingEncoding(NSUTF8StringEncoding) {
let decoder = try getDecoder(keyData)
let signature = try cfTry(.DecodeError) { SecTransformExecute(decoder, $0) }
let signature = try cfTry(.Error) { SecTransformExecute(decoder, $0) }
let verifier = try getVerifier(self.pubKey, signature: signature as! NSData, nameData: nameData)
let result = try cfTry(.VerificationError) { SecTransformExecute(verifier, $0) }
let result = try cfTry(.Error) { SecTransformExecute(verifier, $0) }
let boolResult = result as! CFBooleanRef
return Bool(boolResult)
} else {
Expand All @@ -81,15 +84,15 @@ public struct CocoaFobLicVerifier {
// MARK: - Helper functions

private func getDecoder(keyData: NSData) throws -> SecTransform {
let decoder = try cfTry(.ErrorCreatingDecoderTransform) { return SecDecodeTransformCreate(kSecBase32Encoding, $0) }
try cfTry(.ErrorConfiguringDecoderTransform) { return SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, keyData, $0) }
let decoder = try cfTry(.Error) { return SecDecodeTransformCreate(kSecBase32Encoding, $0) }
try cfTry(.Error) { return SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, keyData, $0) }
return decoder
}

private func getVerifier(publicKey: SecKeyRef, signature: NSData, nameData: NSData) throws -> SecTransform {
let verifier = try cfTry(.ErrorCreatingVerifierTransform) { return SecVerifyTransformCreate(publicKey, signature, $0) }
try cfTry(.ErrorConfiguringVerifierTransform) { return SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, nameData, $0) }
try cfTry(.ErrorConfiguringVerifierTransform) { return SecTransformSetAttribute(verifier, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
let verifier = try cfTry(.Error) { return SecVerifyTransformCreate(publicKey, signature, $0) }
try cfTry(.Error) { return SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, nameData, $0) }
try cfTry(.Error) { return SecTransformSetAttribute(verifier, kSecDigestTypeAttribute, kSecDigestSHA1, $0) }
return verifier
}

Expand Down
Loading

0 comments on commit d38dd66

Please sign in to comment.