├── .gitignore ├── .idea ├── encodings.xml ├── misc.xml └── xcode.xml ├── CHANGELOG ├── LICENSE.txt ├── Package.resolved ├── Package.swift ├── README.md ├── SelfSignedCert.podspec ├── SelfSignedCert.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcshareddata │ └── xcschemes │ └── SelfSignedCert.xcscheme ├── SelfSignedCert ├── ASN1Object.swift ├── BitString.swift ├── CertificateName.swift ├── CertificateRequest.swift ├── DEREncoding.swift ├── Info.plist ├── OID.swift ├── SecCertificate+Keychain.swift ├── SecIdentity+SelfSigned.swift └── SelfSignedCert.h ├── SelfSignedCertTests ├── CertificateNameTests.swift ├── CertificateRequestTests.swift ├── DERTests.swift ├── Info.plist ├── OIDTests.swift ├── SecIdentity+SelfSignedTests.swift ├── certdata.der └── pubkey.bin └── TestHost ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist └── ViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | docs 2 | 3 | # Xcode 4 | build/ 5 | xcuserdata 6 | 7 | # AppCode 8 | **/.idea/*.iml 9 | **/.idea/vcs.xml 10 | **/.idea/runConfigurations 11 | **/.idea/modules.xml 12 | **/.idea/workspace.xml 13 | 14 | # Carthage 15 | Carthage 16 | 17 | .swiftpm 18 | .build 19 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/xcode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Version 3.1.0 2 | ============= 3 | Adds optional `validFrom` and `validTo` to `SecIdentity.create()` (#11; thanks 4 | @bengus!) 5 | 6 | Version 3.0.1 7 | ============= 8 | Adds Swift Package Manager support. 9 | 10 | Version 3.0.0 11 | ============= 12 | Upgraded to Swift 5 (using Xcode 11.6). 13 | 14 | Version 2.0.1 15 | ============= 16 | Added Carthage support. 17 | 18 | Version 2.0.0 19 | ============= 20 | Upgraded to Swift 3 (using Xcode 8.3.2). 21 | 22 | Version 1.0.2 23 | ============= 24 | Updated SecurityExtensions to 2.0.0. 25 | 26 | Version 1.0.1 27 | ============= 28 | Extracted some code into separate project "SecurityExtensions" (see dependencies in podspec and Podfile). 29 | 30 | Version 1.0.0 31 | ============= 32 | Initial version. 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) Copyright (c) 2016 Stefan van den Oord 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "IDZSwiftCommonCrypto", 6 | "repositoryURL": "https://github.com/iosdevzone/IDZSwiftCommonCrypto", 7 | "state": { 8 | "branch": null, 9 | "revision": "d824371e670bd57eb456bbc41139b4997f7207b8", 10 | "version": "0.13.1" 11 | } 12 | }, 13 | { 14 | "package": "SwiftBytes", 15 | "repositoryURL": "https://github.com/dapperstout/swift-bytes.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "570b0b8d8694594a41bba998c5ad82eb711fa2de", 19 | "version": "0.8.0" 20 | } 21 | }, 22 | { 23 | "package": "SecurityExtensions", 24 | "repositoryURL": "https://github.com/svdo/swift-SecurityExtensions", 25 | "state": { 26 | "branch": null, 27 | "revision": "22a6b3ad4afae59e8dd33b0ccb45fa50cb1deab3", 28 | "version": "4.0.1" 29 | } 30 | } 31 | ] 32 | }, 33 | "version": 1 34 | } 35 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "SelfSignedCert", 6 | platforms: [ 7 | .macOS(.v10_15), .iOS(.v13), .tvOS(.v13) 8 | ], 9 | products: [ 10 | // Products define the executables and libraries a package produces, and make them visible to other packages. 11 | .library( 12 | name: "SelfSignedCert", 13 | targets: ["SelfSignedCert"] 14 | ) 15 | ], 16 | dependencies: [ 17 | // Dependencies declare other packages that this package depends on. 18 | .package(url: "https://github.com/iosdevzone/IDZSwiftCommonCrypto", from: "0.13.1"), 19 | .package(name: "SecurityExtensions", url: "https://github.com/svdo/swift-SecurityExtensions", from: "4.0.1"), 20 | .package(name: "SwiftBytes", url: "https://github.com/dapperstout/swift-bytes.git", from: "0.8.0") 21 | ], 22 | targets: [ 23 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 24 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 25 | .target( 26 | name: "SelfSignedCert", 27 | dependencies: ["IDZSwiftCommonCrypto", "SecurityExtensions", "SwiftBytes"], 28 | path: "SelfSignedCert", 29 | exclude: ["Info.plist"] 30 | ) 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | This repo is going to be archived soon because I cannot maintain it anymore. 3 | If you want to be the new 'official' owner/maintainer of this library, please create a fork and let me know via this issue. 4 |
5 | 6 | # SelfSignedCert 7 | 8 | ![Swift Version 5](https://img.shields.io/badge/Swift-v5-yellow.svg) 9 | [![CocoaPods Version Badge](https://img.shields.io/cocoapods/v/SelfSignedCert.svg)](https://cocoapods.org/pods/SelfSignedCert) 10 | [![License Badge](https://img.shields.io/cocoapods/l/SelfSignedCert.svg)](LICENSE.txt) 11 | ![Supported Platforms Badge](https://img.shields.io/cocoapods/p/SelfSignedCert.svg) 12 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 13 | [![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) 14 | 15 | This project provides a Swift framework that allows you to create self-signed 16 | certificates on iOS, using Swift. Unfortunately, Apple does not provide this 17 | functionality in their security frameworks. Another way of doing it is using 18 | OpenSSL, but (especially when using Swift) that is downright horrible. 19 | 20 | The code in this library is a (partial) port of 21 | [MYCrypto](https://github.com/snej/MYCrypto). That project contains unmaintained 22 | Objective-C code, which was difficult to use as a CocoaPod and especially also 23 | when using Swift. So I took that part that I needed and implemented that in 24 | Swift. 25 | 26 | Please note that I'm not a security expert. This framework has not been reviewed 27 | by a security expert. Until it has, please use with caution! And in any case 28 | (reviewed or not), using it is always at your own risk of course. 29 | 30 | If you are a security expert and you want to review this framework, please 31 | contact me. 32 | 33 | ## Usage 34 | 35 | ```swift 36 | guard let identity = SecIdentity.create( 37 | subjectCommonName: "common name", 38 | subjectEmailAddress: "email@example.com") else { 39 | return 40 | } 41 | 42 | ``` 43 | 44 | This will give you a self-signed `SecIdentity?` that is already stored in the 45 | keychain. See also [SecIdentity+SelfSigned.swift][1] for functions to retrieve 46 | previously created identities from the keychain. 47 | 48 | ## Related Library 49 | 50 | You may want to have a look at [swift-SecurityExtensions][2] for some helpers 51 | to more easily use `SecIdentity`, `SecCertificate`, and `SecKey`. 52 | 53 | [1]: https://github.com/svdo/swift-SelfSignedCert/blob/master/SelfSignedCert/SecIdentity%2BSelfSigned.swift 54 | [2]: https://github.com/svdo/swift-SecurityExtensions 55 | -------------------------------------------------------------------------------- /SelfSignedCert.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SelfSignedCert" 3 | s.version = "3.1.0" 4 | s.summary = "A framework for iOS that allows creating self-signed certificates, implemented in Swift." 5 | s.description = <<-DESC 6 | On iOS, you cannot simply create self-signed certificates. 7 | You could try and pull out OpenSSL, but that will turn into 8 | a nightmare very quickly. This library provides functionality 9 | to create self-signed certificates in Swift. DISCLAIMER: I 10 | am no security expert. This library has not been audited by 11 | one. I just ported a part of another library, copying many 12 | of the unit tests in there, but I don't know if they were all 13 | correct... Use at your own risk! By the way: if you are a 14 | security expert and want to audit this library, that would 15 | earn you LOTS and LOTS of gratitude! Please contact me. 16 | DESC 17 | 18 | s.homepage = "https://github.com/svdo/swift-SelfSignedCert" 19 | s.license = { :type => "MIT", :file => "LICENSE.txt" } 20 | s.author = { "Stefan van den Oord" => "soord@mac.com" } 21 | s.platform = :ios, "9.0" 22 | s.source = { :git => "https://github.com/svdo/swift-SelfSignedCert.git", :tag => "#{s.version}" } 23 | s.source_files = "SelfSignedCert/**/*.swift" 24 | s.dependency "SecurityExtensions", "~> 4.0" 25 | s.dependency "IDZSwiftCommonCrypto", "~> 0.13" 26 | s.dependency "SwiftBytes", "~> 0.6" 27 | s.swift_version = '5' 28 | end 29 | -------------------------------------------------------------------------------- /SelfSignedCert.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E2D1DCA625DABD1900114EDE /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = E2D1DCA525DABD1900114EDE /* Nimble */; }; 11 | E2D1DCAC25DABD4C00114EDE /* Quick in Frameworks */ = {isa = PBXBuildFile; productRef = E2D1DCAB25DABD4C00114EDE /* Quick */; }; 12 | E2D1DCE925DABFE300114EDE /* IDZSwiftCommonCrypto in Frameworks */ = {isa = PBXBuildFile; productRef = E2D1DCE825DABFE300114EDE /* IDZSwiftCommonCrypto */; }; 13 | F81B16AF1CEA19FB00C1EBD8 /* OIDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81B16AE1CEA19FB00C1EBD8 /* OIDTests.swift */; }; 14 | F855135C1CE772210023ADEF /* certdata.der in Resources */ = {isa = PBXBuildFile; fileRef = F855135A1CE772210023ADEF /* certdata.der */; }; 15 | F855135D1CE772210023ADEF /* pubkey.bin in Resources */ = {isa = PBXBuildFile; fileRef = F855135B1CE772210023ADEF /* pubkey.bin */; }; 16 | F855135F1CE7AC7F0023ADEF /* ASN1Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = F855135E1CE7AC7F0023ADEF /* ASN1Object.swift */; }; 17 | F85DD02A24EEBCB900446EB7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DD02924EEBCB900446EB7 /* AppDelegate.swift */; }; 18 | F85DD02C24EEBCB900446EB7 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DD02B24EEBCB900446EB7 /* ViewController.swift */; }; 19 | F85DD02F24EEBCB900446EB7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F85DD02D24EEBCB900446EB7 /* Main.storyboard */; }; 20 | F85DD03124EEBCBA00446EB7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F85DD03024EEBCBA00446EB7 /* Assets.xcassets */; }; 21 | F85DD03424EEBCBA00446EB7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F85DD03224EEBCBA00446EB7 /* LaunchScreen.storyboard */; }; 22 | F86D2E001CF48D170036B444 /* SecCertificate+Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86D2DFF1CF48D170036B444 /* SecCertificate+Keychain.swift */; }; 23 | F8825C3A2670B15900867A3F /* SecurityExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = F8825C392670B15900867A3F /* SecurityExtensions */; }; 24 | F8825C3D2670B1DC00867A3F /* SwiftBytes in Frameworks */ = {isa = PBXBuildFile; productRef = F8825C3C2670B1DC00867A3F /* SwiftBytes */; }; 25 | F8B8C5521CDBCCB800FC4174 /* SelfSignedCert.h in Headers */ = {isa = PBXBuildFile; fileRef = F8B8C5511CDBCCB800FC4174 /* SelfSignedCert.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | F8B8C5591CDBCCB800FC4174 /* SelfSignedCert.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8B8C54E1CDBCCB800FC4174 /* SelfSignedCert.framework */; }; 27 | F8B8C55E1CDBCCB800FC4174 /* SecIdentity+SelfSignedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C55D1CDBCCB800FC4174 /* SecIdentity+SelfSignedTests.swift */; }; 28 | F8B8C5691CDBD32A00FC4174 /* SecIdentity+SelfSigned.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C5681CDBD32A00FC4174 /* SecIdentity+SelfSigned.swift */; }; 29 | F8B8C56D1CDBDBBE00FC4174 /* CertificateRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C56C1CDBDBBE00FC4174 /* CertificateRequest.swift */; }; 30 | F8B8C5711CDCDE0F00FC4174 /* CertificateRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C5701CDCDE0F00FC4174 /* CertificateRequestTests.swift */; }; 31 | F8B8C5771CDCF42800FC4174 /* DERTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C5761CDCF42800FC4174 /* DERTests.swift */; }; 32 | F8B8C5791CDE2CFB00FC4174 /* DEREncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C5781CDE2CFB00FC4174 /* DEREncoding.swift */; }; 33 | F8B8C57D1CE4DBA700FC4174 /* OID.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8B8C57C1CE4DBA700FC4174 /* OID.swift */; }; 34 | F8CF9ECD1CE8FC8700702C68 /* BitString.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CF9ECC1CE8FC8700702C68 /* BitString.swift */; }; 35 | F8CF9ECF1CEA024600702C68 /* CertificateName.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CF9ECE1CEA024600702C68 /* CertificateName.swift */; }; 36 | F8CF9ED11CEA081F00702C68 /* CertificateNameTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CF9ED01CEA081F00702C68 /* CertificateNameTests.swift */; }; 37 | /* End PBXBuildFile section */ 38 | 39 | /* Begin PBXContainerItemProxy section */ 40 | F85DD03924EEBCBE00446EB7 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = F8B8C5451CDBCCB800FC4174 /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = F85DD02624EEBCB900446EB7; 45 | remoteInfo = TestHost; 46 | }; 47 | F8B8C55A1CDBCCB800FC4174 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = F8B8C5451CDBCCB800FC4174 /* Project object */; 50 | proxyType = 1; 51 | remoteGlobalIDString = F8B8C54D1CDBCCB800FC4174; 52 | remoteInfo = SelfSignedCert; 53 | }; 54 | /* End PBXContainerItemProxy section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | F81B16AE1CEA19FB00C1EBD8 /* OIDTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OIDTests.swift; sourceTree = ""; }; 58 | F855135A1CE772210023ADEF /* certdata.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = certdata.der; sourceTree = ""; }; 59 | F855135B1CE772210023ADEF /* pubkey.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = pubkey.bin; sourceTree = ""; }; 60 | F855135E1CE7AC7F0023ADEF /* ASN1Object.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Object.swift; sourceTree = ""; }; 61 | F85DD02724EEBCB900446EB7 /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | F85DD02924EEBCB900446EB7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 63 | F85DD02B24EEBCB900446EB7 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 64 | F85DD02E24EEBCB900446EB7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 65 | F85DD03024EEBCBA00446EB7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 66 | F85DD03324EEBCBA00446EB7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 67 | F85DD03524EEBCBA00446EB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | F86D2DFF1CF48D170036B444 /* SecCertificate+Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SecCertificate+Keychain.swift"; sourceTree = ""; }; 69 | F8B8C54E1CDBCCB800FC4174 /* SelfSignedCert.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SelfSignedCert.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | F8B8C5511CDBCCB800FC4174 /* SelfSignedCert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelfSignedCert.h; sourceTree = ""; }; 71 | F8B8C5531CDBCCB800FC4174 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | F8B8C5581CDBCCB800FC4174 /* SelfSignedCertTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfSignedCertTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | F8B8C55D1CDBCCB800FC4174 /* SecIdentity+SelfSignedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SecIdentity+SelfSignedTests.swift"; sourceTree = ""; }; 74 | F8B8C55F1CDBCCB800FC4174 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75 | F8B8C5681CDBD32A00FC4174 /* SecIdentity+SelfSigned.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SecIdentity+SelfSigned.swift"; sourceTree = ""; }; 76 | F8B8C56C1CDBDBBE00FC4174 /* CertificateRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificateRequest.swift; sourceTree = ""; }; 77 | F8B8C5701CDCDE0F00FC4174 /* CertificateRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificateRequestTests.swift; sourceTree = ""; }; 78 | F8B8C5761CDCF42800FC4174 /* DERTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DERTests.swift; sourceTree = ""; }; 79 | F8B8C5781CDE2CFB00FC4174 /* DEREncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DEREncoding.swift; sourceTree = ""; }; 80 | F8B8C57C1CE4DBA700FC4174 /* OID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OID.swift; sourceTree = ""; }; 81 | F8CF9ECC1CE8FC8700702C68 /* BitString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitString.swift; sourceTree = ""; }; 82 | F8CF9ECE1CEA024600702C68 /* CertificateName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificateName.swift; sourceTree = ""; }; 83 | F8CF9ED01CEA081F00702C68 /* CertificateNameTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificateNameTests.swift; sourceTree = ""; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | F85DD02424EEBCB900446EB7 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | F8B8C54A1CDBCCB800FC4174 /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | F8825C3D2670B1DC00867A3F /* SwiftBytes in Frameworks */, 99 | F8825C3A2670B15900867A3F /* SecurityExtensions in Frameworks */, 100 | E2D1DCE925DABFE300114EDE /* IDZSwiftCommonCrypto in Frameworks */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | F8B8C5551CDBCCB800FC4174 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | E2D1DCA625DABD1900114EDE /* Nimble in Frameworks */, 109 | F8B8C5591CDBCCB800FC4174 /* SelfSignedCert.framework in Frameworks */, 110 | E2D1DCAC25DABD4C00114EDE /* Quick in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | /* End PBXFrameworksBuildPhase section */ 115 | 116 | /* Begin PBXGroup section */ 117 | F85DD02824EEBCB900446EB7 /* TestHost */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | F85DD02924EEBCB900446EB7 /* AppDelegate.swift */, 121 | F85DD02B24EEBCB900446EB7 /* ViewController.swift */, 122 | F85DD02D24EEBCB900446EB7 /* Main.storyboard */, 123 | F85DD03024EEBCBA00446EB7 /* Assets.xcassets */, 124 | F85DD03224EEBCBA00446EB7 /* LaunchScreen.storyboard */, 125 | F85DD03524EEBCBA00446EB7 /* Info.plist */, 126 | ); 127 | path = TestHost; 128 | sourceTree = ""; 129 | }; 130 | F86D2E011CF4A4210036B444 /* Supporting files */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | F8B8C5531CDBCCB800FC4174 /* Info.plist */, 134 | F8B8C5511CDBCCB800FC4174 /* SelfSignedCert.h */, 135 | ); 136 | name = "Supporting files"; 137 | sourceTree = ""; 138 | }; 139 | F8B8C5441CDBCCB800FC4174 = { 140 | isa = PBXGroup; 141 | children = ( 142 | F8B8C5501CDBCCB800FC4174 /* SelfSignedCert */, 143 | F8B8C55C1CDBCCB800FC4174 /* SelfSignedCertTests */, 144 | F85DD02824EEBCB900446EB7 /* TestHost */, 145 | F8B8C54F1CDBCCB800FC4174 /* Products */, 146 | ); 147 | sourceTree = ""; 148 | }; 149 | F8B8C54F1CDBCCB800FC4174 /* Products */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | F8B8C54E1CDBCCB800FC4174 /* SelfSignedCert.framework */, 153 | F8B8C5581CDBCCB800FC4174 /* SelfSignedCertTests.xctest */, 154 | F85DD02724EEBCB900446EB7 /* TestHost.app */, 155 | ); 156 | name = Products; 157 | sourceTree = ""; 158 | }; 159 | F8B8C5501CDBCCB800FC4174 /* SelfSignedCert */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | F8B8C5681CDBD32A00FC4174 /* SecIdentity+SelfSigned.swift */, 163 | F8B8C56C1CDBDBBE00FC4174 /* CertificateRequest.swift */, 164 | F8CF9ECE1CEA024600702C68 /* CertificateName.swift */, 165 | F8B8C5781CDE2CFB00FC4174 /* DEREncoding.swift */, 166 | F8B8C57C1CE4DBA700FC4174 /* OID.swift */, 167 | F8CF9ECC1CE8FC8700702C68 /* BitString.swift */, 168 | F855135E1CE7AC7F0023ADEF /* ASN1Object.swift */, 169 | F86D2DFF1CF48D170036B444 /* SecCertificate+Keychain.swift */, 170 | F86D2E011CF4A4210036B444 /* Supporting files */, 171 | ); 172 | path = SelfSignedCert; 173 | sourceTree = ""; 174 | }; 175 | F8B8C55C1CDBCCB800FC4174 /* SelfSignedCertTests */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | F855135A1CE772210023ADEF /* certdata.der */, 179 | F855135B1CE772210023ADEF /* pubkey.bin */, 180 | F8B8C55F1CDBCCB800FC4174 /* Info.plist */, 181 | F8B8C5701CDCDE0F00FC4174 /* CertificateRequestTests.swift */, 182 | F8B8C5761CDCF42800FC4174 /* DERTests.swift */, 183 | F8B8C55D1CDBCCB800FC4174 /* SecIdentity+SelfSignedTests.swift */, 184 | F8CF9ED01CEA081F00702C68 /* CertificateNameTests.swift */, 185 | F81B16AE1CEA19FB00C1EBD8 /* OIDTests.swift */, 186 | ); 187 | path = SelfSignedCertTests; 188 | sourceTree = ""; 189 | }; 190 | /* End PBXGroup section */ 191 | 192 | /* Begin PBXHeadersBuildPhase section */ 193 | F8B8C54B1CDBCCB800FC4174 /* Headers */ = { 194 | isa = PBXHeadersBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | F8B8C5521CDBCCB800FC4174 /* SelfSignedCert.h in Headers */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXHeadersBuildPhase section */ 202 | 203 | /* Begin PBXNativeTarget section */ 204 | F85DD02624EEBCB900446EB7 /* TestHost */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = F85DD03624EEBCBA00446EB7 /* Build configuration list for PBXNativeTarget "TestHost" */; 207 | buildPhases = ( 208 | F85DD02324EEBCB900446EB7 /* Sources */, 209 | F85DD02424EEBCB900446EB7 /* Frameworks */, 210 | F85DD02524EEBCB900446EB7 /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | ); 216 | name = TestHost; 217 | productName = TestHost; 218 | productReference = F85DD02724EEBCB900446EB7 /* TestHost.app */; 219 | productType = "com.apple.product-type.application"; 220 | }; 221 | F8B8C54D1CDBCCB800FC4174 /* SelfSignedCert */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = F8B8C5621CDBCCB800FC4174 /* Build configuration list for PBXNativeTarget "SelfSignedCert" */; 224 | buildPhases = ( 225 | F8B8C5491CDBCCB800FC4174 /* Sources */, 226 | F8B8C54A1CDBCCB800FC4174 /* Frameworks */, 227 | F8B8C54B1CDBCCB800FC4174 /* Headers */, 228 | F8B8C54C1CDBCCB800FC4174 /* Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | ); 234 | name = SelfSignedCert; 235 | packageProductDependencies = ( 236 | E2D1DCE825DABFE300114EDE /* IDZSwiftCommonCrypto */, 237 | F8825C392670B15900867A3F /* SecurityExtensions */, 238 | F8825C3C2670B1DC00867A3F /* SwiftBytes */, 239 | ); 240 | productName = SelfSignedCert; 241 | productReference = F8B8C54E1CDBCCB800FC4174 /* SelfSignedCert.framework */; 242 | productType = "com.apple.product-type.framework"; 243 | }; 244 | F8B8C5571CDBCCB800FC4174 /* SelfSignedCertTests */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = F8B8C5651CDBCCB800FC4174 /* Build configuration list for PBXNativeTarget "SelfSignedCertTests" */; 247 | buildPhases = ( 248 | F8B8C5541CDBCCB800FC4174 /* Sources */, 249 | F8B8C5551CDBCCB800FC4174 /* Frameworks */, 250 | F8B8C5561CDBCCB800FC4174 /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | F8B8C55B1CDBCCB800FC4174 /* PBXTargetDependency */, 256 | F85DD03A24EEBCBE00446EB7 /* PBXTargetDependency */, 257 | ); 258 | name = SelfSignedCertTests; 259 | packageProductDependencies = ( 260 | E2D1DCA525DABD1900114EDE /* Nimble */, 261 | E2D1DCAB25DABD4C00114EDE /* Quick */, 262 | ); 263 | productName = SelfSignedCertTests; 264 | productReference = F8B8C5581CDBCCB800FC4174 /* SelfSignedCertTests.xctest */; 265 | productType = "com.apple.product-type.bundle.unit-test"; 266 | }; 267 | /* End PBXNativeTarget section */ 268 | 269 | /* Begin PBXProject section */ 270 | F8B8C5451CDBCCB800FC4174 /* Project object */ = { 271 | isa = PBXProject; 272 | attributes = { 273 | LastSwiftUpdateCheck = 1010; 274 | LastUpgradeCheck = 1240; 275 | ORGANIZATIONNAME = "Stefan van den Oord"; 276 | TargetAttributes = { 277 | F85DD02624EEBCB900446EB7 = { 278 | CreatedOnToolsVersion = 10.1; 279 | LastSwiftMigration = 1160; 280 | ProvisioningStyle = Automatic; 281 | }; 282 | F8B8C54D1CDBCCB800FC4174 = { 283 | CreatedOnToolsVersion = 7.3.1; 284 | LastSwiftMigration = 1160; 285 | }; 286 | F8B8C5571CDBCCB800FC4174 = { 287 | CreatedOnToolsVersion = 7.3.1; 288 | LastSwiftMigration = 1160; 289 | TestTargetID = F85DD02624EEBCB900446EB7; 290 | }; 291 | }; 292 | }; 293 | buildConfigurationList = F8B8C5481CDBCCB800FC4174 /* Build configuration list for PBXProject "SelfSignedCert" */; 294 | compatibilityVersion = "Xcode 3.2"; 295 | developmentRegion = en; 296 | hasScannedForEncodings = 0; 297 | knownRegions = ( 298 | en, 299 | Base, 300 | ); 301 | mainGroup = F8B8C5441CDBCCB800FC4174; 302 | packageReferences = ( 303 | E2D1DCA425DABD1900114EDE /* XCRemoteSwiftPackageReference "Nimble" */, 304 | E2D1DCAA25DABD4C00114EDE /* XCRemoteSwiftPackageReference "Quick" */, 305 | E2D1DCE725DABFE300114EDE /* XCRemoteSwiftPackageReference "IDZSwiftCommonCrypto" */, 306 | F8825C382670B15900867A3F /* XCRemoteSwiftPackageReference "swift-SecurityExtensions" */, 307 | F8825C3B2670B1DC00867A3F /* XCRemoteSwiftPackageReference "swift-bytes" */, 308 | ); 309 | productRefGroup = F8B8C54F1CDBCCB800FC4174 /* Products */; 310 | projectDirPath = ""; 311 | projectRoot = ""; 312 | targets = ( 313 | F8B8C54D1CDBCCB800FC4174 /* SelfSignedCert */, 314 | F8B8C5571CDBCCB800FC4174 /* SelfSignedCertTests */, 315 | F85DD02624EEBCB900446EB7 /* TestHost */, 316 | ); 317 | }; 318 | /* End PBXProject section */ 319 | 320 | /* Begin PBXResourcesBuildPhase section */ 321 | F85DD02524EEBCB900446EB7 /* Resources */ = { 322 | isa = PBXResourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | F85DD03424EEBCBA00446EB7 /* LaunchScreen.storyboard in Resources */, 326 | F85DD03124EEBCBA00446EB7 /* Assets.xcassets in Resources */, 327 | F85DD02F24EEBCB900446EB7 /* Main.storyboard in Resources */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | F8B8C54C1CDBCCB800FC4174 /* Resources */ = { 332 | isa = PBXResourcesBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | F8B8C5561CDBCCB800FC4174 /* Resources */ = { 339 | isa = PBXResourcesBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | F855135C1CE772210023ADEF /* certdata.der in Resources */, 343 | F855135D1CE772210023ADEF /* pubkey.bin in Resources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXResourcesBuildPhase section */ 348 | 349 | /* Begin PBXSourcesBuildPhase section */ 350 | F85DD02324EEBCB900446EB7 /* Sources */ = { 351 | isa = PBXSourcesBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | F85DD02C24EEBCB900446EB7 /* ViewController.swift in Sources */, 355 | F85DD02A24EEBCB900446EB7 /* AppDelegate.swift in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | F8B8C5491CDBCCB800FC4174 /* Sources */ = { 360 | isa = PBXSourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | F8B8C5691CDBD32A00FC4174 /* SecIdentity+SelfSigned.swift in Sources */, 364 | F8B8C56D1CDBDBBE00FC4174 /* CertificateRequest.swift in Sources */, 365 | F8CF9ECD1CE8FC8700702C68 /* BitString.swift in Sources */, 366 | F8B8C5791CDE2CFB00FC4174 /* DEREncoding.swift in Sources */, 367 | F8CF9ECF1CEA024600702C68 /* CertificateName.swift in Sources */, 368 | F855135F1CE7AC7F0023ADEF /* ASN1Object.swift in Sources */, 369 | F86D2E001CF48D170036B444 /* SecCertificate+Keychain.swift in Sources */, 370 | F8B8C57D1CE4DBA700FC4174 /* OID.swift in Sources */, 371 | ); 372 | runOnlyForDeploymentPostprocessing = 0; 373 | }; 374 | F8B8C5541CDBCCB800FC4174 /* Sources */ = { 375 | isa = PBXSourcesBuildPhase; 376 | buildActionMask = 2147483647; 377 | files = ( 378 | F81B16AF1CEA19FB00C1EBD8 /* OIDTests.swift in Sources */, 379 | F8CF9ED11CEA081F00702C68 /* CertificateNameTests.swift in Sources */, 380 | F8B8C55E1CDBCCB800FC4174 /* SecIdentity+SelfSignedTests.swift in Sources */, 381 | F8B8C5771CDCF42800FC4174 /* DERTests.swift in Sources */, 382 | F8B8C5711CDCDE0F00FC4174 /* CertificateRequestTests.swift in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | F85DD03A24EEBCBE00446EB7 /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = F85DD02624EEBCB900446EB7 /* TestHost */; 392 | targetProxy = F85DD03924EEBCBE00446EB7 /* PBXContainerItemProxy */; 393 | }; 394 | F8B8C55B1CDBCCB800FC4174 /* PBXTargetDependency */ = { 395 | isa = PBXTargetDependency; 396 | target = F8B8C54D1CDBCCB800FC4174 /* SelfSignedCert */; 397 | targetProxy = F8B8C55A1CDBCCB800FC4174 /* PBXContainerItemProxy */; 398 | }; 399 | /* End PBXTargetDependency section */ 400 | 401 | /* Begin PBXVariantGroup section */ 402 | F85DD02D24EEBCB900446EB7 /* Main.storyboard */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | F85DD02E24EEBCB900446EB7 /* Base */, 406 | ); 407 | name = Main.storyboard; 408 | sourceTree = ""; 409 | }; 410 | F85DD03224EEBCBA00446EB7 /* LaunchScreen.storyboard */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | F85DD03324EEBCBA00446EB7 /* Base */, 414 | ); 415 | name = LaunchScreen.storyboard; 416 | sourceTree = ""; 417 | }; 418 | /* End PBXVariantGroup section */ 419 | 420 | /* Begin XCBuildConfiguration section */ 421 | F85DD03724EEBCBA00446EB7 /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 425 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 427 | CLANG_ENABLE_OBJC_WEAK = YES; 428 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 429 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 430 | CODE_SIGN_IDENTITY = "iPhone Developer"; 431 | CODE_SIGN_STYLE = Automatic; 432 | DEVELOPMENT_TEAM = Y4JDW4CJ25; 433 | GCC_C_LANGUAGE_STANDARD = gnu11; 434 | INFOPLIST_FILE = TestHost/Info.plist; 435 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 436 | LD_RUNPATH_SEARCH_PATHS = ( 437 | "$(inherited)", 438 | "@executable_path/Frameworks", 439 | ); 440 | MARKETING_VERSION = 3.1.0; 441 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 442 | MTL_FAST_MATH = YES; 443 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCert.TestHost; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 446 | SWIFT_VERSION = 5.0; 447 | TARGETED_DEVICE_FAMILY = "1,2"; 448 | }; 449 | name = Debug; 450 | }; 451 | F85DD03824EEBCBA00446EB7 /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 455 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 457 | CLANG_ENABLE_OBJC_WEAK = YES; 458 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 459 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 460 | CODE_SIGN_IDENTITY = "iPhone Developer"; 461 | CODE_SIGN_STYLE = Automatic; 462 | DEVELOPMENT_TEAM = Y4JDW4CJ25; 463 | GCC_C_LANGUAGE_STANDARD = gnu11; 464 | INFOPLIST_FILE = TestHost/Info.plist; 465 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 466 | LD_RUNPATH_SEARCH_PATHS = ( 467 | "$(inherited)", 468 | "@executable_path/Frameworks", 469 | ); 470 | MARKETING_VERSION = 3.1.0; 471 | MTL_FAST_MATH = YES; 472 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCert.TestHost; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | SWIFT_VERSION = 5.0; 475 | TARGETED_DEVICE_FAMILY = "1,2"; 476 | }; 477 | name = Release; 478 | }; 479 | F8B8C5601CDBCCB800FC4174 /* Debug */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | ALWAYS_SEARCH_USER_PATHS = NO; 483 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 484 | CLANG_ANALYZER_NONNULL = YES; 485 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 486 | CLANG_CXX_LIBRARY = "libc++"; 487 | CLANG_ENABLE_MODULES = YES; 488 | CLANG_ENABLE_OBJC_ARC = YES; 489 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 490 | CLANG_WARN_BOOL_CONVERSION = YES; 491 | CLANG_WARN_COMMA = YES; 492 | CLANG_WARN_CONSTANT_CONVERSION = YES; 493 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 494 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 495 | CLANG_WARN_EMPTY_BODY = YES; 496 | CLANG_WARN_ENUM_CONVERSION = YES; 497 | CLANG_WARN_INFINITE_RECURSION = YES; 498 | CLANG_WARN_INT_CONVERSION = YES; 499 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 500 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 501 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 502 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 503 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 504 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 505 | CLANG_WARN_STRICT_PROTOTYPES = YES; 506 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 507 | CLANG_WARN_UNREACHABLE_CODE = YES; 508 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 509 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 510 | COPY_PHASE_STRIP = NO; 511 | CURRENT_PROJECT_VERSION = 1; 512 | DEBUG_INFORMATION_FORMAT = dwarf; 513 | ENABLE_STRICT_OBJC_MSGSEND = YES; 514 | ENABLE_TESTABILITY = YES; 515 | GCC_C_LANGUAGE_STANDARD = gnu99; 516 | GCC_DYNAMIC_NO_PIC = NO; 517 | GCC_NO_COMMON_BLOCKS = YES; 518 | GCC_OPTIMIZATION_LEVEL = 0; 519 | GCC_PREPROCESSOR_DEFINITIONS = ( 520 | "DEBUG=1", 521 | "$(inherited)", 522 | ); 523 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 524 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 525 | GCC_WARN_UNDECLARED_SELECTOR = YES; 526 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 527 | GCC_WARN_UNUSED_FUNCTION = YES; 528 | GCC_WARN_UNUSED_VARIABLE = YES; 529 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 530 | MTL_ENABLE_DEBUG_INFO = YES; 531 | ONLY_ACTIVE_ARCH = YES; 532 | SDKROOT = iphoneos; 533 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 534 | SWIFT_VERSION = 3.0; 535 | TARGETED_DEVICE_FAMILY = "1,2"; 536 | VERSIONING_SYSTEM = "apple-generic"; 537 | VERSION_INFO_PREFIX = ""; 538 | }; 539 | name = Debug; 540 | }; 541 | F8B8C5611CDBCCB800FC4174 /* Release */ = { 542 | isa = XCBuildConfiguration; 543 | buildSettings = { 544 | ALWAYS_SEARCH_USER_PATHS = NO; 545 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 546 | CLANG_ANALYZER_NONNULL = YES; 547 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 548 | CLANG_CXX_LIBRARY = "libc++"; 549 | CLANG_ENABLE_MODULES = YES; 550 | CLANG_ENABLE_OBJC_ARC = YES; 551 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 552 | CLANG_WARN_BOOL_CONVERSION = YES; 553 | CLANG_WARN_COMMA = YES; 554 | CLANG_WARN_CONSTANT_CONVERSION = YES; 555 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 556 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 557 | CLANG_WARN_EMPTY_BODY = YES; 558 | CLANG_WARN_ENUM_CONVERSION = YES; 559 | CLANG_WARN_INFINITE_RECURSION = YES; 560 | CLANG_WARN_INT_CONVERSION = YES; 561 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 562 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 563 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 564 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 565 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 566 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 567 | CLANG_WARN_STRICT_PROTOTYPES = YES; 568 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 569 | CLANG_WARN_UNREACHABLE_CODE = YES; 570 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 571 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 572 | COPY_PHASE_STRIP = NO; 573 | CURRENT_PROJECT_VERSION = 1; 574 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 575 | ENABLE_NS_ASSERTIONS = NO; 576 | ENABLE_STRICT_OBJC_MSGSEND = YES; 577 | GCC_C_LANGUAGE_STANDARD = gnu99; 578 | GCC_NO_COMMON_BLOCKS = YES; 579 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 580 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 581 | GCC_WARN_UNDECLARED_SELECTOR = YES; 582 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 583 | GCC_WARN_UNUSED_FUNCTION = YES; 584 | GCC_WARN_UNUSED_VARIABLE = YES; 585 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 586 | MTL_ENABLE_DEBUG_INFO = NO; 587 | SDKROOT = iphoneos; 588 | SWIFT_COMPILATION_MODE = wholemodule; 589 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 590 | SWIFT_VERSION = 3.0; 591 | TARGETED_DEVICE_FAMILY = "1,2"; 592 | VALIDATE_PRODUCT = YES; 593 | VERSIONING_SYSTEM = "apple-generic"; 594 | VERSION_INFO_PREFIX = ""; 595 | }; 596 | name = Release; 597 | }; 598 | F8B8C5631CDBCCB800FC4174 /* Debug */ = { 599 | isa = XCBuildConfiguration; 600 | buildSettings = { 601 | CLANG_ENABLE_MODULES = YES; 602 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 603 | DEFINES_MODULE = YES; 604 | DYLIB_COMPATIBILITY_VERSION = 1; 605 | DYLIB_CURRENT_VERSION = 1; 606 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 607 | INFOPLIST_FILE = SelfSignedCert/Info.plist; 608 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 609 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 610 | LD_RUNPATH_SEARCH_PATHS = ( 611 | "$(inherited)", 612 | "@executable_path/Frameworks", 613 | "@loader_path/Frameworks", 614 | ); 615 | MARKETING_VERSION = 3.1.0; 616 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCert; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SKIP_INSTALL = YES; 619 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 620 | SWIFT_VERSION = 5.0; 621 | }; 622 | name = Debug; 623 | }; 624 | F8B8C5641CDBCCB800FC4174 /* Release */ = { 625 | isa = XCBuildConfiguration; 626 | buildSettings = { 627 | CLANG_ENABLE_MODULES = YES; 628 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 629 | DEFINES_MODULE = YES; 630 | DYLIB_COMPATIBILITY_VERSION = 1; 631 | DYLIB_CURRENT_VERSION = 1; 632 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 633 | INFOPLIST_FILE = SelfSignedCert/Info.plist; 634 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 635 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 636 | LD_RUNPATH_SEARCH_PATHS = ( 637 | "$(inherited)", 638 | "@executable_path/Frameworks", 639 | "@loader_path/Frameworks", 640 | ); 641 | MARKETING_VERSION = 3.1.0; 642 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCert; 643 | PRODUCT_NAME = "$(TARGET_NAME)"; 644 | SKIP_INSTALL = YES; 645 | SWIFT_VERSION = 5.0; 646 | }; 647 | name = Release; 648 | }; 649 | F8B8C5661CDBCCB800FC4174 /* Debug */ = { 650 | isa = XCBuildConfiguration; 651 | buildSettings = { 652 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 653 | DEVELOPMENT_TEAM = Y4JDW4CJ25; 654 | INFOPLIST_FILE = SelfSignedCertTests/Info.plist; 655 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 656 | LD_RUNPATH_SEARCH_PATHS = ( 657 | "$(inherited)", 658 | "@executable_path/Frameworks", 659 | "@loader_path/Frameworks", 660 | ); 661 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCertTests; 662 | PRODUCT_NAME = "$(TARGET_NAME)"; 663 | SWIFT_VERSION = 5.0; 664 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost"; 665 | }; 666 | name = Debug; 667 | }; 668 | F8B8C5671CDBCCB800FC4174 /* Release */ = { 669 | isa = XCBuildConfiguration; 670 | buildSettings = { 671 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 672 | DEVELOPMENT_TEAM = Y4JDW4CJ25; 673 | INFOPLIST_FILE = SelfSignedCertTests/Info.plist; 674 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 675 | LD_RUNPATH_SEARCH_PATHS = ( 676 | "$(inherited)", 677 | "@executable_path/Frameworks", 678 | "@loader_path/Frameworks", 679 | ); 680 | PRODUCT_BUNDLE_IDENTIFIER = com.vandenoord.SelfSignedCertTests; 681 | PRODUCT_NAME = "$(TARGET_NAME)"; 682 | SWIFT_VERSION = 5.0; 683 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost"; 684 | }; 685 | name = Release; 686 | }; 687 | /* End XCBuildConfiguration section */ 688 | 689 | /* Begin XCConfigurationList section */ 690 | F85DD03624EEBCBA00446EB7 /* Build configuration list for PBXNativeTarget "TestHost" */ = { 691 | isa = XCConfigurationList; 692 | buildConfigurations = ( 693 | F85DD03724EEBCBA00446EB7 /* Debug */, 694 | F85DD03824EEBCBA00446EB7 /* Release */, 695 | ); 696 | defaultConfigurationIsVisible = 0; 697 | defaultConfigurationName = Release; 698 | }; 699 | F8B8C5481CDBCCB800FC4174 /* Build configuration list for PBXProject "SelfSignedCert" */ = { 700 | isa = XCConfigurationList; 701 | buildConfigurations = ( 702 | F8B8C5601CDBCCB800FC4174 /* Debug */, 703 | F8B8C5611CDBCCB800FC4174 /* Release */, 704 | ); 705 | defaultConfigurationIsVisible = 0; 706 | defaultConfigurationName = Release; 707 | }; 708 | F8B8C5621CDBCCB800FC4174 /* Build configuration list for PBXNativeTarget "SelfSignedCert" */ = { 709 | isa = XCConfigurationList; 710 | buildConfigurations = ( 711 | F8B8C5631CDBCCB800FC4174 /* Debug */, 712 | F8B8C5641CDBCCB800FC4174 /* Release */, 713 | ); 714 | defaultConfigurationIsVisible = 0; 715 | defaultConfigurationName = Release; 716 | }; 717 | F8B8C5651CDBCCB800FC4174 /* Build configuration list for PBXNativeTarget "SelfSignedCertTests" */ = { 718 | isa = XCConfigurationList; 719 | buildConfigurations = ( 720 | F8B8C5661CDBCCB800FC4174 /* Debug */, 721 | F8B8C5671CDBCCB800FC4174 /* Release */, 722 | ); 723 | defaultConfigurationIsVisible = 0; 724 | defaultConfigurationName = Release; 725 | }; 726 | /* End XCConfigurationList section */ 727 | 728 | /* Begin XCRemoteSwiftPackageReference section */ 729 | E2D1DCA425DABD1900114EDE /* XCRemoteSwiftPackageReference "Nimble" */ = { 730 | isa = XCRemoteSwiftPackageReference; 731 | repositoryURL = "https://github.com/Quick/Nimble"; 732 | requirement = { 733 | kind = upToNextMajorVersion; 734 | minimumVersion = 9.0.0; 735 | }; 736 | }; 737 | E2D1DCAA25DABD4C00114EDE /* XCRemoteSwiftPackageReference "Quick" */ = { 738 | isa = XCRemoteSwiftPackageReference; 739 | repositoryURL = "https://github.com/Quick/Quick"; 740 | requirement = { 741 | kind = upToNextMajorVersion; 742 | minimumVersion = 3.1.2; 743 | }; 744 | }; 745 | E2D1DCE725DABFE300114EDE /* XCRemoteSwiftPackageReference "IDZSwiftCommonCrypto" */ = { 746 | isa = XCRemoteSwiftPackageReference; 747 | repositoryURL = "https://github.com/iosdevzone/IDZSwiftCommonCrypto"; 748 | requirement = { 749 | kind = upToNextMajorVersion; 750 | minimumVersion = 0.13.1; 751 | }; 752 | }; 753 | F8825C382670B15900867A3F /* XCRemoteSwiftPackageReference "swift-SecurityExtensions" */ = { 754 | isa = XCRemoteSwiftPackageReference; 755 | repositoryURL = "https://github.com/svdo/swift-SecurityExtensions.git"; 756 | requirement = { 757 | kind = upToNextMajorVersion; 758 | minimumVersion = 4.0.1; 759 | }; 760 | }; 761 | F8825C3B2670B1DC00867A3F /* XCRemoteSwiftPackageReference "swift-bytes" */ = { 762 | isa = XCRemoteSwiftPackageReference; 763 | repositoryURL = "https://github.com/dapperstout/swift-bytes.git"; 764 | requirement = { 765 | kind = upToNextMajorVersion; 766 | minimumVersion = 0.8.0; 767 | }; 768 | }; 769 | /* End XCRemoteSwiftPackageReference section */ 770 | 771 | /* Begin XCSwiftPackageProductDependency section */ 772 | E2D1DCA525DABD1900114EDE /* Nimble */ = { 773 | isa = XCSwiftPackageProductDependency; 774 | package = E2D1DCA425DABD1900114EDE /* XCRemoteSwiftPackageReference "Nimble" */; 775 | productName = Nimble; 776 | }; 777 | E2D1DCAB25DABD4C00114EDE /* Quick */ = { 778 | isa = XCSwiftPackageProductDependency; 779 | package = E2D1DCAA25DABD4C00114EDE /* XCRemoteSwiftPackageReference "Quick" */; 780 | productName = Quick; 781 | }; 782 | E2D1DCE825DABFE300114EDE /* IDZSwiftCommonCrypto */ = { 783 | isa = XCSwiftPackageProductDependency; 784 | package = E2D1DCE725DABFE300114EDE /* XCRemoteSwiftPackageReference "IDZSwiftCommonCrypto" */; 785 | productName = IDZSwiftCommonCrypto; 786 | }; 787 | F8825C392670B15900867A3F /* SecurityExtensions */ = { 788 | isa = XCSwiftPackageProductDependency; 789 | package = F8825C382670B15900867A3F /* XCRemoteSwiftPackageReference "swift-SecurityExtensions" */; 790 | productName = SecurityExtensions; 791 | }; 792 | F8825C3C2670B1DC00867A3F /* SwiftBytes */ = { 793 | isa = XCSwiftPackageProductDependency; 794 | package = F8825C3B2670B1DC00867A3F /* XCRemoteSwiftPackageReference "swift-bytes" */; 795 | productName = SwiftBytes; 796 | }; 797 | /* End XCSwiftPackageProductDependency section */ 798 | }; 799 | rootObject = F8B8C5451CDBCCB800FC4174 /* Project object */; 800 | } 801 | -------------------------------------------------------------------------------- /SelfSignedCert.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SelfSignedCert.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SelfSignedCert.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CwlCatchException", 6 | "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "f809deb30dc5c9d9b78c872e553261a61177721a", 10 | "version": "2.0.0" 11 | } 12 | }, 13 | { 14 | "package": "CwlPreconditionTesting", 15 | "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "02b7a39a99c4da27abe03cab2053a9034379639f", 19 | "version": "2.0.0" 20 | } 21 | }, 22 | { 23 | "package": "IDZSwiftCommonCrypto", 24 | "repositoryURL": "https://github.com/iosdevzone/IDZSwiftCommonCrypto", 25 | "state": { 26 | "branch": null, 27 | "revision": "d824371e670bd57eb456bbc41139b4997f7207b8", 28 | "version": "0.13.1" 29 | } 30 | }, 31 | { 32 | "package": "Nimble", 33 | "repositoryURL": "https://github.com/Quick/Nimble", 34 | "state": { 35 | "branch": null, 36 | "revision": "e491a6731307bb23783bf664d003be9b2fa59ab5", 37 | "version": "9.0.0" 38 | } 39 | }, 40 | { 41 | "package": "Quick", 42 | "repositoryURL": "https://github.com/Quick/Quick", 43 | "state": { 44 | "branch": null, 45 | "revision": "8cce6acd38f965f5baa3167b939f86500314022b", 46 | "version": "3.1.2" 47 | } 48 | }, 49 | { 50 | "package": "SwiftBytes", 51 | "repositoryURL": "https://github.com/dapperstout/swift-bytes.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "570b0b8d8694594a41bba998c5ad82eb711fa2de", 55 | "version": "0.8.0" 56 | } 57 | }, 58 | { 59 | "package": "SecurityExtensions", 60 | "repositoryURL": "https://github.com/svdo/swift-SecurityExtensions.git", 61 | "state": { 62 | "branch": null, 63 | "revision": "22a6b3ad4afae59e8dd33b0ccb45fa50cb1deab3", 64 | "version": "4.0.1" 65 | } 66 | } 67 | ] 68 | }, 69 | "version": 1 70 | } 71 | -------------------------------------------------------------------------------- /SelfSignedCert.xcodeproj/xcshareddata/xcschemes/SelfSignedCert.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /SelfSignedCert/ASN1Object.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | 5 | class ASN1Object : NSObject { 6 | let tag: UInt8 7 | let tagClass: UInt8 8 | let components: [NSObject]? 9 | let constructed: Bool 10 | let value: [UInt8]? 11 | 12 | convenience init(tag:UInt8, tagClass:UInt8, components:[NSObject]) { 13 | self.init(tag:tag, tagClass:tagClass, components:components, constructed:false, value:nil) 14 | } 15 | 16 | convenience init(tag:UInt8, tagClass:UInt8, constructed:Bool, value:[UInt8]) { 17 | self.init(tag:tag, tagClass:tagClass, components:nil, constructed:constructed, value:value) 18 | } 19 | 20 | private init(tag:UInt8, tagClass:UInt8, components:[NSObject]?, constructed:Bool, value:[UInt8]?) { 21 | self.tag = tag 22 | self.tagClass = tagClass 23 | self.constructed = constructed 24 | self.value = value 25 | self.components = components 26 | } 27 | 28 | override var description: String { 29 | if components != nil { 30 | return String(format:"\(type(of: self))[%hhu/%u/%u]%@", tagClass, constructed ? 1 : 0, tag, components!); 31 | } 32 | else { 33 | return String(format:"\(type(of: self))[%hhu/%u/%u, %u bytes]", tagClass, constructed ? 1 : 0, tag, value!.count); 34 | } 35 | 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /SelfSignedCert/BitString.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | 5 | class BitString : NSObject { 6 | let data: [UInt8] 7 | let bitCount: UInt 8 | 9 | convenience init(data:Data) { 10 | self.init(bytes: data.bytes) 11 | } 12 | 13 | init(bytes:[UInt8]) { 14 | self.data = bytes 15 | bitCount = UInt(data.count) * 8 16 | } 17 | 18 | override var description: String { 19 | return "\(type(of: self))\(data)" 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SelfSignedCert/CertificateName.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | 5 | class CertificateName : NSObject { 6 | private(set) var components: [ Set ] 7 | 8 | var commonName: String { 9 | get { return string(for: OID.commonName) } 10 | set { setString(newValue, forOid:OID.commonName) } 11 | } 12 | var emailAddress: String { 13 | get { return string(for: OID.email) } 14 | set { setString(newValue, forOid:OID.email) } 15 | } 16 | 17 | override init() { 18 | components = [] 19 | super.init() 20 | } 21 | 22 | func string(for oid:OID) -> String { 23 | guard let pair = pair(for: oid), let str = pair[1] as? String else { 24 | return "" 25 | } 26 | return str 27 | } 28 | 29 | func setString(_ string:String, forOid oid:OID) { 30 | if let pair = pair(for: oid) { 31 | pair[1] = string 32 | } 33 | else { 34 | components.append([[oid, string]]) 35 | } 36 | } 37 | 38 | private func pair(for oid:OID) -> NSMutableArray? { 39 | let filtered = components.filter { set in 40 | guard let array = set.first, let filteredOid = array[0] as? OID else { 41 | return false 42 | } 43 | return filteredOid == oid 44 | } 45 | if filtered.count == 1 { 46 | return filtered[0].first 47 | } 48 | else { 49 | return nil 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /SelfSignedCert/CertificateRequest.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | import Security 5 | 6 | /** 7 | * Option set used for specifying key usage in certificate requests. 8 | */ 9 | struct KeyUsage : OptionSet { 10 | let rawValue: UInt16 11 | init(rawValue: UInt16) { self.rawValue = rawValue } 12 | 13 | static let DigitalSignature = KeyUsage(rawValue: 0x80) 14 | static let NonRepudiation = KeyUsage(rawValue: 0x40) 15 | static let KeyEncipherment = KeyUsage(rawValue: 0x20) 16 | static let DataEncipherment = KeyUsage(rawValue: 0x10) 17 | static let KeyAgreement = KeyUsage(rawValue: 0x08) 18 | static let KeyCertSign = KeyUsage(rawValue: 0x04) 19 | static let CRLSign = KeyUsage(rawValue: 0x02) 20 | static let EncipherOnly = KeyUsage(rawValue: 0x01) 21 | static let DecipherOnly = KeyUsage(rawValue: 0x100) 22 | static let Unspecified = KeyUsage(rawValue: 0xFFFF) // Returned if key-usage extension is not present 23 | } 24 | 25 | func ==(lhs: KeyUsage, rhs: KeyUsage) -> Bool { 26 | return lhs.rawValue == rhs.rawValue 27 | } 28 | 29 | /** 30 | * Represents a certificate request. 31 | */ 32 | struct CertificateRequest { 33 | var publicKey : SecKey 34 | var subjectCommonName: String 35 | var subjectEmailAddress: String 36 | var serialNumber: UInt64 37 | var validFrom: Date 38 | var validTo: Date 39 | var publicKeyDerEncoder: ((SecKey) -> [UInt8]?)? 40 | var keyUsage: KeyUsage 41 | 42 | init(forPublicKey key:SecKey, subjectCommonName:String, subjectEmailAddress:String, keyUsage:KeyUsage, 43 | validFrom:Date? = nil, validTo:Date? = nil, serialNumber:UInt64? = nil) { 44 | self.publicKey = key 45 | self.subjectCommonName = subjectCommonName 46 | self.subjectEmailAddress = subjectEmailAddress 47 | if let from = validFrom { 48 | self.validFrom = from 49 | } 50 | else { 51 | self.validFrom = Date() 52 | } 53 | if let to = validTo { 54 | self.validTo = to 55 | } 56 | else { 57 | self.validTo = self.validFrom.addingTimeInterval(365*24*3600) 58 | } 59 | 60 | if let serial = serialNumber { 61 | self.serialNumber = serial 62 | } 63 | else { 64 | self.serialNumber = UInt64(CFAbsoluteTimeGetCurrent() * 1000) 65 | } 66 | self.keyUsage = keyUsage 67 | 68 | publicKeyDerEncoder = encodePublicKey 69 | } 70 | 71 | func encodePublicKey(_ key:SecKey) -> [UInt8]? { 72 | return key.keyData 73 | } 74 | 75 | func selfSign(withPrivateKey key:SecKey) -> [UInt8]? { 76 | guard let info = self.info(usingSubjectAsIssuer:true) else { 77 | return nil 78 | } 79 | 80 | let dataToSign = info.toDER() 81 | guard let signedData = key.sign(data:dataToSign) else { 82 | return nil 83 | } 84 | let signature = BitString(data: Data(signedData)) 85 | 86 | let signedInfo: NSArray = [ info, [OID.rsaWithSHA1AlgorithmID, NSNull()], signature] 87 | return signedInfo.toDER() 88 | } 89 | } 90 | 91 | extension CertificateRequest { 92 | func info(usingSubjectAsIssuer: Bool = false) -> NSArray? { 93 | precondition(publicKeyDerEncoder != nil) 94 | 95 | let empty = NSNull() 96 | let version = ASN1Object( 97 | tag:0, tagClass:2, components:[ 98 | NSNumber(value: 3 /*kCertRequestVersionNumber*/ - 1 ) 99 | ] 100 | ) 101 | guard let bytes = publicKeyDerEncoder?(publicKey) else { 102 | return nil 103 | } 104 | let encodedPubKey = Data(bytes) 105 | let pubKeyBitStringArray : NSArray = [ [OID.rsaAlgorithmID, empty], BitString(data:encodedPubKey) ] 106 | let subject = CertificateName() 107 | subject.commonName = subjectCommonName 108 | subject.emailAddress = subjectEmailAddress 109 | let ext = ASN1Object(tag: 3, tagClass: 2, components: [extensions() as NSObject]) 110 | let subjectComponents = subject.components 111 | let info : NSArray = [ 112 | version, NSNumber(value: serialNumber as UInt64), [ OID.rsaAlgorithmID ], usingSubjectAsIssuer ? subjectComponents : [], [validFrom, validTo], 113 | subjectComponents, pubKeyBitStringArray, ext 114 | ] 115 | return info 116 | } 117 | 118 | func toDER() -> [UInt8]? { 119 | return info()?.toDER() 120 | } 121 | 122 | func extensions() -> [NSArray] { 123 | var extensions = [NSArray]() 124 | 125 | let keyUsageMask: UInt16 = keyUsage.rawValue 126 | if keyUsageMask != KeyUsage.Unspecified.rawValue { 127 | var bytes: [UInt8] = [0,0] 128 | bytes[0] = UInt8(keyUsageMask & 0xff) 129 | bytes[1] = UInt8(keyUsageMask >> 8) 130 | let length = 1 + ((bytes[1] != 0) ? 1 : 0) 131 | let data = Data(bytes: bytes, count: length) 132 | let bitString = BitString(data:data) 133 | let encodedBitString = bitString.toDER() 134 | extensions.append([OID.keyUsageOID, true/*critical*/, Data(encodedBitString)]) 135 | } 136 | 137 | return extensions 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /SelfSignedCert/DEREncoding.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | import SwiftBytes 5 | 6 | extension NSNull { 7 | func toDER() -> [UInt8] { 8 | return writeDER(tag: 5, constructed: false, bytes: []) 9 | } 10 | } 11 | 12 | extension Bool { 13 | func toDER() -> [UInt8] { 14 | let value : UInt8 = self ? 0xFF : 0x00 15 | return writeDER(tag:1, constructed:false, bytes:[value]) 16 | } 17 | } 18 | 19 | extension UnsignedInteger { 20 | func encodeForDER() -> [UInt8] { 21 | var bytes : [UInt8] = SwiftBytes.bytes(UInt64(self)).removeLeadingZeros() 22 | if (bytes[0] & 0x80) == 0x80 { 23 | bytes = [0x00] + bytes 24 | } 25 | return bytes 26 | } 27 | func toDER() -> [UInt8] { 28 | return writeDER(tag: 2, constructed: false, bytes: self.encodeForDER()) 29 | } 30 | } 31 | 32 | extension BinaryInteger { 33 | func toDER() -> [UInt8] { 34 | if self >= 0 { 35 | return UInt64(self).toDER() 36 | } 37 | else { 38 | let bitPattern = ~(-Int64(self)) + 1 39 | let twosComplement = UInt64(bitPattern:bitPattern) 40 | let bytes : [UInt8] = SwiftBytes.bytes(twosComplement).ensureSingleLeadingOneBit() 41 | return writeDER(tag: 2, constructed: false, bytes: bytes) 42 | } 43 | } 44 | } 45 | 46 | extension Sequence where Iterator.Element : BinaryInteger { 47 | func removeLeading(_ number:Iterator.Element) -> [Iterator.Element] { 48 | if self.min() == nil { return [] } 49 | var nonNumberFound = false 50 | let flat = self.compactMap { (elem:Iterator.Element) -> Iterator.Element? in 51 | if (elem == number && !nonNumberFound ) { 52 | return nil 53 | } else { 54 | nonNumberFound = true 55 | return elem 56 | } 57 | } 58 | return flat 59 | } 60 | 61 | func removeLeadingZeros() -> [Iterator.Element] { 62 | if self.min() == nil { return [] } 63 | let removedZeros = self.removeLeading(0) 64 | if removedZeros.count == 0 { 65 | return [0] 66 | } 67 | else { 68 | return removedZeros 69 | } 70 | } 71 | 72 | func ensureSingleLeadingOneBit() -> [Iterator.Element] { 73 | if self.min() == nil { return [] } 74 | let removedFF = self.removeLeading(0xFF) 75 | if removedFF.count == 0 { 76 | return [0xFF] 77 | } 78 | else if removedFF[0] & 0x80 != 0x80 { 79 | return [0xFF] + removedFF 80 | } 81 | return removedFF 82 | } 83 | } 84 | 85 | extension String { 86 | 87 | private static let notPrintableCharSet : NSMutableCharacterSet = { 88 | let charset = NSMutableCharacterSet(charactersIn:" '()+,-./:=?") 89 | charset.formUnion(with: CharacterSet.alphanumerics); 90 | charset.invert(); 91 | return charset; 92 | }() 93 | 94 | func toDER() -> [UInt8] { 95 | if let asciiData = self.data(using: String.Encoding.ascii) { 96 | var tag:UInt8 = 19; // printablestring (a silly arbitrary subset of ASCII defined by ASN.1) 97 | if let range = self.rangeOfCharacter(from: String.notPrintableCharSet as CharacterSet), /*!forcePrintableStrings && */range.upperBound > range.lowerBound { 98 | tag = 20 // IA5string (full 7-bit ASCII) 99 | } 100 | return writeDER(tag: tag, tagClass: 0, constructed: false, bytes: asciiData.bytes) 101 | } else { 102 | let utf8Bytes = [UInt8](self.utf8) 103 | return writeDER(tag: 12, constructed: false, bytes: utf8Bytes) 104 | } 105 | } 106 | } 107 | 108 | extension BitString { 109 | func toDER() -> [UInt8] { 110 | let bytes = writeDERHeader(tag: 3, tagClass: 0, constructed: false, length: UInt64(1+bitCount/8)) 111 | let unused = UInt8((8 - (bitCount % 8)) % 8) 112 | return bytes + [unused] + data 113 | } 114 | } 115 | 116 | var berGeneralizedTimeFormatter: DateFormatter { 117 | let df = DateFormatter() 118 | df.dateFormat = "yyyyMMddHHmmss'Z'" 119 | df.timeZone = TimeZone(identifier: "GMT") 120 | df.locale = Locale(identifier: "nb") 121 | return df 122 | } 123 | 124 | extension Date { 125 | func toDER() -> [UInt8] { 126 | let dateString = berGeneralizedTimeFormatter.string(from: self) 127 | return writeDER(tag: 24, constructed: false, bytes: [UInt8](dateString.utf8)) 128 | } 129 | } 130 | 131 | extension Data { 132 | func toDER() -> [UInt8] { 133 | return writeDER(tag: 4, tagClass: 0, constructed: false, bytes: self.bytes) 134 | } 135 | } 136 | 137 | extension OID { 138 | func toDER() -> [UInt8] { 139 | var bytes = [UInt8]() 140 | var index = 0 141 | if (components.count >= 2 && components[0] <= 3 && components[1] < 40) { 142 | bytes.append(UInt8(components[0]) * 40 + UInt8(components[1])) 143 | index = 2 144 | } 145 | while index < components.count { 146 | var nonZeroAdded = false 147 | let component = components[index] 148 | for shift in stride(from: 28, through: 0, by: -7) { 149 | let byte = UInt8((component >> UInt32(shift)) & 0x7F) 150 | if (byte != 0 || nonZeroAdded) { 151 | if (nonZeroAdded) { 152 | bytes[bytes.count-1] |= 0x80 153 | } 154 | bytes.append(byte) 155 | nonZeroAdded = true 156 | } 157 | } 158 | index = index + 1 159 | } 160 | return writeDER(tag: 6, tagClass: 0, constructed: false, bytes: bytes) 161 | } 162 | } 163 | 164 | struct DERSequence { 165 | let contentsGenerator:()->[UInt8] 166 | func toDER() -> [UInt8] { 167 | return writeDER(tag: 16, constructed: true, bytes: contentsGenerator()) 168 | } 169 | } 170 | 171 | extension ASN1Object { 172 | func toDER() -> [UInt8] { 173 | if let comps = self.components { 174 | return encodeCollection(comps, tag: self.tag, tagClass: self.tagClass) 175 | } 176 | else if let data = self.value { 177 | return writeDER(tag: self.tag, tagClass: self.tagClass, constructed: self.constructed, bytes: data) 178 | } 179 | else { 180 | assertionFailure("ASN1Object should have either components or value, but has neither") 181 | return [] 182 | } 183 | } 184 | } 185 | 186 | extension NSArray { 187 | func toDER() -> [UInt8] { 188 | var objects = self as? [NSObject] 189 | if objects == nil { 190 | var copy = Array() 191 | for o in self { 192 | copy.append(o as! NSObject) 193 | } 194 | objects = copy 195 | } 196 | guard let collection = objects else { 197 | assertionFailure("Unable to endcode array") 198 | return [] 199 | } 200 | return encodeCollection(collection, tag:16, tagClass: 0) 201 | } 202 | } 203 | 204 | extension NSSet { 205 | func toDER() -> [UInt8] { 206 | var objects = [NSObject]() 207 | for o in self { 208 | objects.append(o as! NSObject) 209 | } 210 | return encodeCollection(objects, tag: 17, tagClass: 0) 211 | } 212 | } 213 | 214 | extension Sequence where Iterator.Element == NSObject { 215 | 216 | } 217 | 218 | extension NSNumber { 219 | func toDER() -> [UInt8] { 220 | // Special-case detection of booleans by pointer equality, because otherwise they appear 221 | // identical to 0 and 1: 222 | if (self===NSNumber(value: true) || self===NSNumber(value: false)) { 223 | let value:UInt8 = self===NSNumber(value: true) ?0xFF :0x00; 224 | return writeDER(tag: 1, constructed: false, bytes: [value]) 225 | } 226 | 227 | guard let objcType = String(validatingUTF8: self.objCType) else { 228 | assertionFailure("Could not get objcType of NSNumber") 229 | return [] 230 | } 231 | 232 | if (objcType.count == 1) { 233 | switch(objcType) { 234 | case "c", "i", "s", "l", "q": 235 | return self.int64Value.toDER() 236 | case "C", "I", "S", "L", "Q": 237 | return self.uint64Value.toDER() 238 | case "B": 239 | return self.boolValue.toDER() 240 | default: 241 | assertionFailure("Cannot DER encode NSNumber of type \(objcType)") 242 | return [] 243 | } 244 | } 245 | 246 | assertionFailure("Cannot DER encode NSNumber of type \(objcType)") 247 | return [] 248 | } 249 | } 250 | 251 | extension NSObject { 252 | func toDER_manualDispatch() -> [UInt8] { 253 | if let d = self as? Date { 254 | // print("Date to DER: \(d)") 255 | let bytes = d.toDER() 256 | // print("Date to DER: \(d) -> \(bytes)") 257 | return bytes 258 | } 259 | else if let n = self as? NSNull { 260 | // print("NULL to DER") 261 | let bytes = n.toDER() 262 | // print("NULL to DER -> bytes") 263 | return bytes 264 | } 265 | else if let a = self as? NSArray { 266 | // print("Array to DER {") 267 | let bytes = a.toDER() 268 | // print("} -> \(bytes)") 269 | return bytes 270 | } 271 | else if let s = self as? NSSet { 272 | // print("Set to DER <") 273 | let bytes = s.toDER() 274 | // print("> -> \(bytes)") 275 | return bytes 276 | } 277 | else if let num = self as? NSNumber { 278 | // print("Number to DER: \(num)") 279 | let bytes = num.toDER() 280 | // print("Number to DER: \(num) -> \(bytes)") 281 | return bytes 282 | } 283 | else if let str = self as? NSString { 284 | // print("String to DER: \(str)") 285 | let bytes = (str as String).toDER() 286 | // print("String to DER: \(str) -> \(bytes)") 287 | return bytes 288 | } 289 | else if let asn1 = self as? ASN1Object { 290 | // print("ASN1Object to DER: \(asn1)") 291 | let bytes = asn1.toDER() 292 | // print("ASN1Object to DER: \(asn1) -> \(bytes)") 293 | return bytes 294 | } 295 | else if let oid = self as? OID { 296 | // print("OID to DER: \(oid)") 297 | let bytes = oid.toDER() 298 | // print("OID to DER: \(oid) -> \(bytes)") 299 | return bytes 300 | } 301 | else if let bitStr = self as? BitString { 302 | // print("Bitstring to DER: \(bitStr)") 303 | let bytes = bitStr.toDER() 304 | // print("Bitstring to DER: \(bitStr) -> \(bytes)") 305 | return bytes 306 | } 307 | else if let data = self as? Data { 308 | // print("Data to DER: \(data)") 309 | let bytes = data.toDER() 310 | // print("Data to DER: \(data) -> \(bytes)") 311 | return bytes 312 | } 313 | else { 314 | assertionFailure("toDER_manualDispatch not defined for object \(self)") 315 | return [] 316 | } 317 | } 318 | } 319 | 320 | private func encodeCollection(_ collection:[NSObject], tag:UInt8, tagClass:UInt8) -> [UInt8] { 321 | var bytes = [UInt8]() 322 | for o in collection { 323 | bytes += o.toDER_manualDispatch() 324 | } 325 | return writeDER(tag: tag, tagClass: tagClass, constructed: true, bytes: bytes) 326 | } 327 | 328 | func writeDER(tag:UInt8, tagClass:UInt8 = 0, constructed:Bool, bytes:[UInt8]) -> [UInt8] { 329 | return writeDERHeader(tag: tag, tagClass: tagClass, constructed: constructed, length: UInt64(bytes.count)) + bytes 330 | } 331 | 332 | func writeDERHeader(tag:UInt8, tagClass:UInt8 = 0, constructed:Bool, length:UInt64) -> [UInt8] { 333 | let constructedBits : UInt8 = (constructed ? 1 : 0) << 5 334 | let classBits : UInt8 = tagClass << 6 335 | let headerByte1 : UInt8 = tag | constructedBits | classBits 336 | 337 | var headerByte2 : UInt8 = 0 338 | var headerExtraLength = [UInt8]() 339 | if length < 128 { 340 | headerByte2 = UInt8(length) 341 | } 342 | else { 343 | let l = UInt64(length) 344 | headerExtraLength = l.encodeForDER() 345 | headerByte2 = UInt8(headerExtraLength.count) | 0x80 346 | } 347 | return [headerByte1] + [headerByte2] + headerExtraLength 348 | } 349 | -------------------------------------------------------------------------------- /SelfSignedCert/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SelfSignedCert/OID.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | 5 | class OID : NSObject { 6 | let components: [UInt32] 7 | init(components: [UInt32]) { 8 | self.components = components 9 | super.init() 10 | } 11 | 12 | override func isEqual(_ object: Any?) -> Bool { 13 | guard let other = object as? OID else { 14 | return false 15 | } 16 | return components == other.components 17 | } 18 | 19 | override var hash: Int { 20 | var hash : Int = 0 21 | for i in components { 22 | hash = hash &+ Int(i) 23 | } 24 | return hash 25 | } 26 | 27 | override var description: String { 28 | var desc = "{" 29 | for c in components { 30 | desc += String(format: "%u ", c) 31 | } 32 | return desc + "}" 33 | } 34 | } 35 | 36 | extension OID { 37 | 38 | /** ALGORITHMS **/ 39 | @nonobjc static let rsaAlgorithmID = OID(components:[1, 2, 840, 113549, 1, 1, 1]) 40 | @nonobjc static let rsaWithSHA1AlgorithmID = OID(components:[1, 2, 840, 113549, 1, 1, 5]) 41 | // static let rsaWithSHA256AlgorithmID = OID(components:[1, 2, 840, 113549, 1, 1, 11]) 42 | // static let rsaWithMD5AlgorithmID = OID(components:[1, 2, 840, 113549, 1, 1, 4 ]) 43 | // static let rsaWithMD2AlgorithmID = OID(components:[1, 2, 840, 113549, 1, 1, 2]) 44 | 45 | /** SUBJECT **/ 46 | @nonobjc static let commonName = OID(components:[2, 5, 4, 3]) 47 | // static let givenNameOID = OID(components:[2, 5, 4, 42]) 48 | // static let surnameOID = OID(components:[2, 5, 4, 4]) 49 | // static let descriptionOID = OID(components:[2, 5, 4, 13]) 50 | @nonobjc static let email = OID(components:[1, 2, 840, 113549, 1, 9, 1]) 51 | 52 | /** USAGE **/ 53 | // static let basicConstraintsOID = OID(components:[2, 5, 29, 19]) 54 | @nonobjc static let keyUsageOID = OID(components:[2, 5, 29, 15]) 55 | // static let extendedKeyUsageOID = OID(components:[2, 5, 29, 37]) 56 | 57 | /** EXTENSIONS **/ 58 | // static let extendedKeyUsageServerAuthOID = OID(components:[1, 3, 6, 1, 5, 5, 7, 3, 1]) 59 | // static let extendedKeyUsageClientAuthOID = OID(components:[1, 3, 6, 1, 5, 5, 7, 3, 2]) 60 | // static let extendedKeyUsageCodeSigningOID = OID(components:[1, 3, 6, 1, 5, 5, 7, 3, 3]) 61 | // static let extendedKeyUsageEmailProtectionOID = OID(components:[1, 3, 6, 1, 5, 5, 7, 3, 4]) 62 | // static let extendedKeyUsageAnyOID = OID(components:[2, 5, 29, 37, 0]) 63 | // static let subjectAltNameOID = OID(components:[2, 5, 29, 17]) 64 | 65 | } 66 | -------------------------------------------------------------------------------- /SelfSignedCert/SecCertificate+Keychain.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | 5 | extension SecCertificate { 6 | func storeInKeychain() -> OSStatus { 7 | let dict : [NSString:AnyObject] = [kSecClass as NSString: kSecClassCertificate as NSString, 8 | kSecValueRef as NSString : self] 9 | return SecItemAdd(dict as CFDictionary, nil) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /SelfSignedCert/SecIdentity+SelfSigned.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | import Security 5 | import IDZSwiftCommonCrypto 6 | import SecurityExtensions 7 | 8 | extension SecIdentity 9 | { 10 | 11 | /** 12 | * Create an identity using a self-signed certificate. This can fail in many ways, in which case it will return `nil`. 13 | * Since potential failures are non-recoverable, no details are provided in that case. 14 | * 15 | * - parameter ofSize: size of the keys, in bits; default is 3072 16 | * - parameter subjectCommonName: the common name of the subject of the self-signed certificate that is created 17 | * - parameter subjectEmailAddress: the email address of the subject of the self-signed certificate that is created 18 | * - returns: The created identity, or `nil` when there was an error. 19 | */ 20 | public static func create( 21 | ofSize bits:UInt = 3072, 22 | subjectCommonName name:String, 23 | subjectEmailAddress email:String, 24 | validFrom:Date? = nil, 25 | validTo:Date? = nil 26 | ) -> SecIdentity? { 27 | let privKey: SecKey 28 | let pubKey: SecKey 29 | do { 30 | (privKey,pubKey) = try SecKey.generateKeyPair(ofSize: bits) 31 | } 32 | catch { 33 | return nil 34 | } 35 | let certRequest = CertificateRequest( 36 | forPublicKey:pubKey, 37 | subjectCommonName: name, 38 | subjectEmailAddress: email, 39 | keyUsage: [.DigitalSignature, .DataEncipherment], 40 | validFrom: validFrom, 41 | validTo: validTo 42 | ) 43 | 44 | guard let signedBytes = certRequest.selfSign(withPrivateKey:privKey), 45 | let signedCert = SecCertificateCreateWithData(nil, Data(signedBytes) as CFData) else { 46 | return nil 47 | } 48 | 49 | let err = signedCert.storeInKeychain() 50 | guard err == errSecSuccess else { 51 | return nil 52 | } 53 | 54 | return findIdentity(forPrivateKey:privKey, publicKey:pubKey) 55 | } 56 | 57 | /** 58 | * Helper method that tries to load an identity from the keychain. 59 | * 60 | * - parameter forPrivateKey: the private key for which the identity should be searched 61 | * - parameter publicKey: the public key for which the identity should be searched; should match the private key 62 | * - returns: The identity if found, or `nil`. 63 | */ 64 | private static func findIdentity(forPrivateKey privKey:SecKey, publicKey pubKey:SecKey) -> SecIdentity? { 65 | guard let identity = SecIdentity.find(withPublicKey:pubKey) else { 66 | return nil 67 | } 68 | 69 | // Since the way identities are stored in the keychain is sparsely documented at best, 70 | // double-check that this identity is the one we're looking for. 71 | guard let priv = identity.privateKey, 72 | let retrievedKeyData = priv.keyData, 73 | let originalKeyData = privKey.keyData, retrievedKeyData == originalKeyData else { 74 | return nil 75 | } 76 | 77 | return identity 78 | } 79 | 80 | /** 81 | * Finds the identity in the keychain based on the given public key. 82 | * The identity that is returned is the one that has the public key's digest 83 | * as label. 84 | * 85 | * - parameter withPublicKey: the public key that should be used to find the identity, based on it's digest 86 | * - returns: The identity if found, or `nil`. 87 | */ 88 | public static func find(withPublicKey pubKey:SecKey) -> SecIdentity? { 89 | guard let identities = findAll(withPublicKey: pubKey), identities.count == 1 else { 90 | return nil 91 | } 92 | return identities[0] 93 | } 94 | 95 | /** 96 | * Finds all identities in the keychain based on the given public key. 97 | * The identities that are returned are the ones that have the public key's digest 98 | * as label. Because of the keychain query filters, and on current iOS versions, 99 | * this should return 0 or 1 identity, not more... 100 | * 101 | * - parameter withPublicKey: the public key that should be used to find the identity, based on it's digest 102 | * - returns: an array of identities if found, or `nil` 103 | */ 104 | static func findAll(withPublicKey pubKey:SecKey) -> [SecIdentity]? { 105 | guard let keyData = pubKey.keyData else { 106 | return nil 107 | } 108 | let sha1 = Digest(algorithm: .sha1) 109 | _ = sha1.update(buffer: keyData, byteCount: keyData.count) 110 | let digest = sha1.final() 111 | let digestData = Data(digest) 112 | 113 | var out: AnyObject? 114 | let query : [NSString:AnyObject] = [kSecClass as NSString: kSecClassIdentity as NSString, 115 | kSecAttrKeyClass as NSString: kSecAttrKeyClassPrivate as NSString, 116 | kSecMatchLimit as NSString : kSecMatchLimitAll as NSString, 117 | kSecReturnRef as NSString : NSNumber(value: true), 118 | kSecAttrApplicationLabel as NSString : digestData as NSData ] 119 | let err = SecItemCopyMatching(query as CFDictionary, &out) 120 | guard err == errSecSuccess else { 121 | return nil 122 | } 123 | let identities = out! as! [SecIdentity] 124 | return identities 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /SelfSignedCert/SelfSignedCert.h: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | #import 4 | 5 | //! Project version number for SelfSignedCert. 6 | FOUNDATION_EXPORT double SelfSignedCertVersionNumber; 7 | 8 | //! Project version string for SelfSignedCert. 9 | FOUNDATION_EXPORT const unsigned char SelfSignedCertVersionString[]; 10 | 11 | // In this header, you should import all the public headers of your framework using statements like #import 12 | 13 | 14 | -------------------------------------------------------------------------------- /SelfSignedCertTests/CertificateNameTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Quick 4 | import Nimble 5 | @testable import SelfSignedCert 6 | 7 | class CertificateNameTests: QuickSpec { 8 | 9 | override func spec() { 10 | it("can be constructed") { 11 | expect(CertificateName()).toNot(throwError()) 12 | } 13 | 14 | it("can have common name") { 15 | let cn = CertificateName() 16 | cn.commonName = "test" 17 | expect(cn.commonName) == "test" 18 | } 19 | 20 | it("can have email") { 21 | let cn = CertificateName() 22 | cn.emailAddress = "xx@example.com" 23 | expect(cn.emailAddress) == "xx@example.com" 24 | } 25 | 26 | it("can have both common name and email") { 27 | let cn = CertificateName() 28 | cn.commonName = "test" 29 | cn.emailAddress = "xx@example.com" 30 | expect(cn.commonName) == "test" 31 | expect(cn.emailAddress) == "xx@example.com" 32 | } 33 | 34 | it("can replace common name") { 35 | let cn = CertificateName() 36 | cn.commonName = "test" 37 | cn.commonName = "other" 38 | expect(cn.commonName) == "other" 39 | } 40 | 41 | xit("can replace email") { 42 | let cn = CertificateName() 43 | cn.emailAddress = "x@example.com" 44 | cn.emailAddress = "y@example.com" 45 | expect(cn.emailAddress) == "y@example.com" 46 | } 47 | 48 | context("when setting common name") { 49 | it("has correct internal structure") { 50 | let cn = CertificateName() 51 | cn.commonName = "test" 52 | expect(cn.components.count) == 1 53 | let set:Set = cn.components[0] 54 | expect(set.count) == 1 55 | let array:NSArray = set.first! 56 | expect(array.count) == 2 57 | expect(array[0]) === OID.commonName 58 | expect(array[1] as? String) == "test" 59 | } 60 | } 61 | 62 | context("when setting common name and email") { 63 | it("has correct internal structure") { 64 | let cn = CertificateName() 65 | cn.commonName = "test" 66 | cn.emailAddress = "xx@example.com" 67 | expect(cn.components.count) == 2 68 | 69 | var set:Set = cn.components[0] 70 | expect(set.count) == 1 71 | var array:NSArray = set.first! 72 | expect(array.count) == 2 73 | expect(array[0]) === OID.commonName 74 | expect(array[1] as? String) == "test" 75 | 76 | set = cn.components[1] 77 | expect(set.count) == 1 78 | array = set.first! 79 | expect(array.count) == 2 80 | expect(array[0]) === OID.email 81 | expect(array[1] as? String) == "xx@example.com" 82 | } 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /SelfSignedCertTests/CertificateRequestTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import XCTest 4 | import Quick 5 | import Nimble 6 | import IDZSwiftCommonCrypto 7 | @testable import SelfSignedCert 8 | 9 | class CertificateRequestTests: QuickSpec { 10 | 11 | var dateComponents: DateComponents { 12 | var dc = DateComponents() 13 | dc.year = 2016 14 | dc.month = 5 15 | dc.day = 14 16 | dc.hour = 16 17 | dc.minute = 32 18 | dc.second = 0 19 | dc.timeZone = TimeZone(secondsFromGMT: 0) 20 | return dc 21 | } 22 | var validFrom: Date { 23 | let calendar = Calendar(identifier: Calendar.Identifier.gregorian) 24 | return calendar.date(from: dateComponents)! 25 | } 26 | var validTo: Date { 27 | let calendar = Calendar(identifier: Calendar.Identifier.gregorian) 28 | var dc = dateComponents 29 | dc.year = dc.year! + 1 30 | return calendar.date(from: dc)! 31 | } 32 | 33 | override func spec() { 34 | 35 | var pubKey: SecKey! 36 | 37 | beforeSuite { 38 | do { 39 | // doing this in `beforeSuite` instead of `beforeEach` makes the tests run faster... 40 | let (_, pub) = try SecKey.generateKeyPair(ofSize: 2048) 41 | pubKey = pub 42 | } 43 | catch {} 44 | } 45 | 46 | it("Can construct certificate request") { 47 | expect { () -> Void in 48 | let certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "Test Name", subjectEmailAddress: "test@example.com", keyUsage: [.DigitalSignature, .DataEncipherment]) 49 | expect(certReq.subjectCommonName) == "Test Name" 50 | expect(certReq.subjectEmailAddress) == "test@example.com" 51 | expect(certReq.keyUsage) == [.DigitalSignature, .DataEncipherment] 52 | expect(certReq.publicKey) === pubKey 53 | }.toNot(throwError()) 54 | } 55 | 56 | it("Has default field values") { 57 | expect { () -> Void in 58 | let certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "Test Name", subjectEmailAddress: "test@example.com", keyUsage: [.DigitalSignature, .DataEncipherment]) 59 | expect(certReq.serialNumber) != 0 60 | expect(fabs(certReq.validFrom.timeIntervalSinceNow)).to(beLessThan(1)) 61 | expect(fabs(certReq.validTo.timeIntervalSince(certReq.validFrom) - 365*24*3600)).to(beLessThan(1)) 62 | }.toNot(throwError()) 63 | } 64 | 65 | describe("key usage") { 66 | it("is stored correctly in extensions") { 67 | expect { () -> Void in 68 | let certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "Test Name", subjectEmailAddress: "test@example.com", keyUsage: [.DigitalSignature, .DataEncipherment]) 69 | let extensions = certReq.extensions() 70 | expect(extensions.count) == 1 71 | let ext = extensions[0] 72 | expect(ext[0] as? OID) == OID.keyUsageOID 73 | expect(ext[1] as? NSNumber) == NSNumber(value: true) 74 | let bitsData = ext[2] as! Data 75 | let bytes = bitsData.bytes 76 | expect(bytes.count) == 4 77 | expect(UInt16(bytes[3])) == KeyUsage.DigitalSignature.rawValue | KeyUsage.DataEncipherment.rawValue 78 | }.toNot(throwError()) 79 | } 80 | } 81 | 82 | it("can be DER encoded with preserialized public key") { 83 | var certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "J.R. 'Bob' Dobbs", subjectEmailAddress: "bob@subgenius.org", keyUsage: [.DigitalSignature, .DataEncipherment], validFrom:self.validFrom, validTo:self.validTo, serialNumber:484929458750) 84 | certReq.publicKeyDerEncoder = { pubKey in 85 | let pubKeyPath = Bundle(for: self.classForCoder).path(forResource:"pubkey", ofType: "bin") 86 | let nsData = NSData(contentsOfFile: pubKeyPath!)! 87 | return (nsData as Data).bytes 88 | } 89 | 90 | let certDataPath = Bundle(for: self.classForCoder).path(forResource: "certdata", ofType: "der") 91 | let nsData = NSData(contentsOfFile: certDataPath!)! 92 | let expectedEncoded = (nsData as Data).bytes 93 | 94 | let encoded = certReq.toDER() 95 | // print(dumpData(encoded!, prefix:"", separator:"")) 96 | // print("---") 97 | // print(dumpData(expectedEncoded, prefix:"", separator:"")) 98 | expect(encoded) == expectedEncoded 99 | } 100 | 101 | it("can be DER encoded with public key") { 102 | let certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "J.R. 'Bob' Dobbs", subjectEmailAddress: "bob@subgenius.org", keyUsage: [.DigitalSignature, .DataEncipherment], validFrom:self.validFrom, validTo:self.validTo, serialNumber:484929458750) 103 | let encoded = certReq.toDER()! 104 | expect(encoded.count) == 444 /* same as previous test */ 105 | } 106 | 107 | it("Can sign") { 108 | expect { () -> Void in 109 | let (privKey, pubKey) = try SecKey.generateKeyPair(ofSize: 2048) 110 | let certReq = CertificateRequest(forPublicKey: pubKey, subjectCommonName: "Test Name", subjectEmailAddress: "test@example.com", keyUsage: [.DigitalSignature, .DataEncipherment]) 111 | let signedBytes = certReq.selfSign(withPrivateKey: privKey)! 112 | let signedData = Data(signedBytes) 113 | let signedCert = SecCertificateCreateWithData(nil, signedData as CFData) 114 | expect(signedCert).toNot(beNil()) 115 | let subjectSummary = SecCertificateCopySubjectSummary(signedCert!) 116 | expect(subjectSummary).toNot(beNil()) 117 | expect(subjectSummary! as String) == "Test Name" 118 | 119 | /* 120 | * The remainder of this test shows how the keychain is used to retrieve the SecIdentity that belongs to the signed certificate. 121 | * This is not very well documented, and there was some trial and error involved, so let's make sure that this keeps working 122 | * the way we expect it to. 123 | */ 124 | 125 | /* the identity is not available yet */ 126 | var identity = SecIdentity.find(withPublicKey:pubKey) 127 | expect(identity).to(beNil()) 128 | 129 | /* store in keychain */ 130 | let dict : [NSString:AnyObject] = [ 131 | kSecClass as NSString: kSecClassCertificate as NSString, 132 | kSecValueRef as NSString : signedCert!] 133 | let osresult = SecItemAdd(dict as CFDictionary, nil) 134 | expect(osresult) == errSecSuccess 135 | 136 | /* now we can retrieve the identity */ 137 | identity = SecIdentity.find(withPublicKey:pubKey) 138 | expect(identity).toNot(beNil()) 139 | 140 | /* verify: same private key */ 141 | var identityPrivateKey : SecKey? 142 | expect(SecIdentityCopyPrivateKey(identity!, &identityPrivateKey)) == errSecSuccess 143 | expect(identityPrivateKey!.keyData) == privKey.keyData 144 | 145 | /* verify: same certificate */ 146 | var identityCertificate : SecCertificate? 147 | expect(SecIdentityCopyCertificate(identity!, &identityCertificate)) == errSecSuccess 148 | let identityCertificateData : Data = SecCertificateCopyData(identityCertificate!) as Data 149 | let expectedCertificateData : Data = SecCertificateCopyData(signedCert!) as Data 150 | expect(identityCertificateData.bytes) == expectedCertificateData.bytes 151 | 152 | /* verify: same public key */ 153 | var trust:SecTrust? 154 | let policy = SecPolicyCreateBasicX509(); 155 | expect(SecTrustCreateWithCertificates(identityCertificate!, policy, &trust)) == errSecSuccess 156 | let identityCertificatePublicKey = SecTrustCopyPublicKey(trust!) 157 | expect(identityCertificatePublicKey!.keyData) == pubKey.keyData 158 | 159 | /* verify: signing with retrieved key gives same result */ 160 | let signedBytes2 = certReq.selfSign(withPrivateKey: identityPrivateKey!) 161 | expect(signedBytes) == signedBytes2 162 | }.toNot(throwError()) 163 | } 164 | 165 | } 166 | } 167 | 168 | private func dumpData(_ data:[UInt8], prefix:String = "0x", separator:String = " ") -> String { 169 | var str = "" 170 | for b in data { 171 | if str.count > 0 { 172 | str += separator 173 | } 174 | str += prefix + String(format: "%.2x", b) 175 | } 176 | return str 177 | } 178 | -------------------------------------------------------------------------------- /SelfSignedCertTests/DERTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Foundation 4 | import Quick 5 | import Nimble 6 | import SwiftBytes 7 | @testable import SelfSignedCert 8 | 9 | class DERTests : QuickSpec { 10 | 11 | override func spec() { 12 | 13 | describe("DER encoding") { 14 | it("can encode NULL") { 15 | expect(NSNull().toDER()) == [0x05, 0x00] 16 | } 17 | 18 | it("can encode booleans") { 19 | expect(true.toDER()) == [0x01,0x01,0xFF] 20 | expect(false.toDER()) == [0x01,0x01,0x00] 21 | } 22 | 23 | it("can encode integers") { 24 | expect(0.toDER()) == [0x02,0x01,0x00] 25 | expect(1.toDER()) == [0x02,0x01,0x01] 26 | expect((-1).toDER()) == [0x02,0x01,0xFF] 27 | expect(72.toDER()) == [0x02,0x01,0x48] 28 | expect((-128).toDER()) == [0x02,0x01,0x80] 29 | expect(128.toDER()) == [0x02,0x02,0x00,0x80] 30 | expect(255.toDER()) == [0x02,0x02,0x00,0xFF] 31 | expect((-256).toDER()) == [0x02,0x02,0xFF,0x00] 32 | expect(12345.toDER()) == [0x02,0x02,0x30,0x39] 33 | expect((-12345).toDER()) == [0x02,0x02,0xCF,0xC7] 34 | expect(123456789.toDER()) == [0x02,0x04,0x07,0x5B,0xCD,0x15] 35 | expect((-123456789).toDER()) == [0x02,0x04,0xF8,0xA4,0x32,0xEB] 36 | } 37 | 38 | it("can encode strings") { 39 | expect("".toDER()) == [0x13, 0x00] 40 | expect("hello".toDER()) == [0x13, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f] 41 | expect("thérè".toDER()) == [0x0c, 0x07, 0x74, 0x68, 0xc3, 0xa9, 0x72, 0xc3, 0xa8] 42 | } 43 | 44 | it("can encode a long string") { 45 | let str = "Lorém ipsum dolor sit amet, consectetur adipiscing elit. Aliquam in felis a libero pharetra pellentesque. Mauris et dui vel velit vulputate iaculis eget non orci. Pellentesque magna mauris, finibus et dolor eget, convallis placerat est. Suspendisse ac finibus diam, sed iaculis nulla. Aliquam eu gravida magna. Maecenas aliquam arcu ut odio convallis laoreet. Pellentesque augue dui, feugiat nec felis pharetra, lacinia vulputate risus. Quisque at orci libero. Vestibulum blandit ipsum vel libero elementum, vestibulum interdum nibh tincidunt. Cras eu elementum urna. Integer quis magna sed quam aliquam suscipit." 46 | 47 | // var out = "" 48 | // for b in str.toDER() { 49 | // out += String(format: "0x%.2x, ", b) 50 | // } 51 | // print(out) 52 | expect(str.toDER()) == [0x0c, 0x82, 0x02, 0x66, 0x4c, 0x6f, 0x72, 0xc3, 0xa9, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x69, 0x6e, 0x20, 0x66, 0x65, 0x6c, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x62, 0x65, 0x72, 0x6f, 0x20, 0x70, 0x68, 0x61, 0x72, 0x65, 0x74, 0x72, 0x61, 0x20, 0x70, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x74, 0x65, 0x73, 0x71, 0x75, 0x65, 0x2e, 0x20, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x64, 0x75, 0x69, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x76, 0x75, 0x6c, 0x70, 0x75, 0x74, 0x61, 0x74, 0x65, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6c, 0x69, 0x73, 0x20, 0x65, 0x67, 0x65, 0x74, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x63, 0x69, 0x2e, 0x20, 0x50, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x74, 0x65, 0x73, 0x71, 0x75, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x73, 0x2c, 0x20, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x75, 0x73, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x65, 0x67, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x72, 0x61, 0x74, 0x20, 0x65, 0x73, 0x74, 0x2e, 0x20, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x73, 0x73, 0x65, 0x20, 0x61, 0x63, 0x20, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x75, 0x73, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6c, 0x69, 0x73, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x61, 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x75, 0x20, 0x67, 0x72, 0x61, 0x76, 0x69, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x2e, 0x20, 0x4d, 0x61, 0x65, 0x63, 0x65, 0x6e, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x61, 0x72, 0x63, 0x75, 0x20, 0x75, 0x74, 0x20, 0x6f, 0x64, 0x69, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x20, 0x6c, 0x61, 0x6f, 0x72, 0x65, 0x65, 0x74, 0x2e, 0x20, 0x50, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x74, 0x65, 0x73, 0x71, 0x75, 0x65, 0x20, 0x61, 0x75, 0x67, 0x75, 0x65, 0x20, 0x64, 0x75, 0x69, 0x2c, 0x20, 0x66, 0x65, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x6e, 0x65, 0x63, 0x20, 0x66, 0x65, 0x6c, 0x69, 0x73, 0x20, 0x70, 0x68, 0x61, 0x72, 0x65, 0x74, 0x72, 0x61, 0x2c, 0x20, 0x6c, 0x61, 0x63, 0x69, 0x6e, 0x69, 0x61, 0x20, 0x76, 0x75, 0x6c, 0x70, 0x75, 0x74, 0x61, 0x74, 0x65, 0x20, 0x72, 0x69, 0x73, 0x75, 0x73, 0x2e, 0x20, 0x51, 0x75, 0x69, 0x73, 0x71, 0x75, 0x65, 0x20, 0x61, 0x74, 0x20, 0x6f, 0x72, 0x63, 0x69, 0x20, 0x6c, 0x69, 0x62, 0x65, 0x72, 0x6f, 0x2e, 0x20, 0x56, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6c, 0x75, 0x6d, 0x20, 0x62, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x74, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x6c, 0x69, 0x62, 0x65, 0x72, 0x6f, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x75, 0x6d, 0x2c, 0x20, 0x76, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6c, 0x75, 0x6d, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x64, 0x75, 0x6d, 0x20, 0x6e, 0x69, 0x62, 0x68, 0x20, 0x74, 0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x43, 0x72, 0x61, 0x73, 0x20, 0x65, 0x75, 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x75, 0x6d, 0x20, 0x75, 0x72, 0x6e, 0x61, 0x2e, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x2e] 53 | } 54 | 55 | it("can encode bitstring") { 56 | let str = "test" 57 | let data = str.data(using: String.Encoding.utf8)! 58 | let bitString = BitString(data: data) 59 | expect(bitString.toDER()) == [0x03, 0x05, 0x00, 0x74, 0x65, 0x73, 0x74] 60 | } 61 | 62 | it("can encode dates") { 63 | expect(Date(timeIntervalSinceReferenceDate: 265336576).toDER()) == [0x18, 0x0F] + [UInt8]("20090530003616Z".utf8) 64 | } 65 | 66 | it("can encode simple sequence") { 67 | let sequence = DERSequence { 72.toDER() + true.toDER() } 68 | expect(sequence.toDER()) == [0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF] 69 | 70 | let sequence2 = DERSequence { 42.toDER() + "hello world".toDER() + false.toDER() } 71 | expect(sequence2.toDER()) == [0x30, 0x13, 0x02, 0x01, 0x2A, 0x13, 0x0B, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x01, 0x01, 0x00] 72 | } 73 | 74 | it("can encode nested sequence") { 75 | let sequence = DERSequence { 76 | DERSequence { 72.toDER() + true.toDER() }.toDER() + 77 | DERSequence { 72.toDER() + true.toDER() }.toDER() 78 | } 79 | expect(sequence.toDER()) == [0x30, 0x10, 80 | 0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF, 81 | 0x30, 0x06, 0x02, 0x01, 0x48, 0x01, 0x01, 0xFF] 82 | } 83 | 84 | describe("OID") { 85 | it("can encode empty OID") { 86 | expect(OID(components:[]).toDER()) == [0x06, 0x00] 87 | } 88 | 89 | it("collapses first two bytes if required") { 90 | expect(OID(components:[0,2]).toDER()) == [0x06, 0x01, 0x02] 91 | expect(OID(components:[1,2]).toDER()) == [0x06, 0x01, 0x2a] 92 | expect(OID(components:[2,3]).toDER()) == [0x06, 0x01, 0x53] 93 | expect(OID(components:[4,1]).toDER()) != [0x06, 0x01, 0xA1] 94 | expect(OID(components:[1,42]).toDER()) != [0x06, 0x01, 0x52] 95 | } 96 | 97 | it("can encode OID 1") { 98 | let oidComponents : [UInt32] = [1,2,840,113549,1,1,1] 99 | let oid = OID(components:oidComponents) 100 | expect(oid.toDER()) == [0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01] 101 | } 102 | 103 | it("can encode OID 2") { 104 | let oidComponents : [UInt32] = [2,5,4,4] 105 | let oid = OID(components:oidComponents) 106 | expect(oid.toDER()) == [0x06, 0x03, 0x55, 0x04, 0x04] 107 | } 108 | 109 | it("can encode OID 3") { 110 | expect(OID(components: [1, 2, 840, 113549, 1, 9, 1]).toDER()) == [0x06, 0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x01] 111 | } 112 | } 113 | 114 | describe("ASN.1 Objects") { 115 | it("can encode ASN.1 object with components") { 116 | expect(ASN1Object(tag:0, tagClass:2, components:[NSNumber(value:2 as Int)]).toDER()) == [0xa0, 0x03, 0x02, 0x01, 0x02] 117 | } 118 | it("can encode ASN.1 object without components") { 119 | let data = [UInt8]("test".utf8) 120 | expect(ASN1Object(tag:1, tagClass:2, constructed:false, value:data).toDER()) == [0x81, 0x04, 0x74, 0x65, 0x73, 0x74] 121 | expect(ASN1Object(tag:2, tagClass:0, constructed:true, value:data).toDER()) == [0x22, 0x04, 0x74, 0x65, 0x73, 0x74] 122 | } 123 | } 124 | 125 | describe("Array") { 126 | it("can encode an array") { 127 | let array:NSArray = [42, "hoi", true]; 128 | expect(array.toDER()) == [0x30, 0x0b, 0x02, 0x01, 0x2a, 0x13, 0x03, 0x68, 0x6f, 0x69, 0x01, 0x01, 0xff] 129 | } 130 | } 131 | 132 | describe("Nested array") { 133 | it("can encode a nested array") { 134 | let nestedArray:NSArray = [ [42, "höi", true] ]; 135 | expect(nestedArray.toDER()) == [0x30, 0x0e, 0x30, 0x0c, 0x02, 0x01, 0x2a, 0x0c, 0x04, 0x68, 0xc3, 0xb6, 0x69, 0x01, 0x01, 0xff] 136 | } 137 | } 138 | 139 | describe("Set") { 140 | it("can encode a set") { 141 | let set:NSSet = [42, "höi", true] 142 | expect(set.toDER()) == [0x31, 0x0c, 0x02, 0x01, 0x2a, 0x0c, 0x04, 0x68, 0xc3, 0xb6, 0x69, 0x01, 0x01, 0xff] 143 | } 144 | } 145 | } 146 | 147 | describe("Leading zeros") { 148 | it ("can remove leading zeros") { 149 | expect([UInt8]().removeLeadingZeros()) == [] 150 | expect([0].removeLeadingZeros()) == [0] 151 | expect([1].removeLeadingZeros()) == [1] 152 | expect([0,0].removeLeadingZeros()) == [0] 153 | expect([1,0].removeLeadingZeros()) == [1,0] 154 | expect([0,1].removeLeadingZeros()) == [1] 155 | expect([1,1].removeLeadingZeros()) == [1,1] 156 | } 157 | 158 | it ("can compress leading 0xFF") { 159 | expect([UInt8]().ensureSingleLeadingOneBit()) == [] 160 | expect([0].ensureSingleLeadingOneBit()) == [0xFF, 0] 161 | expect([1].ensureSingleLeadingOneBit()) == [0xFF, 1] 162 | expect([0xFF].ensureSingleLeadingOneBit()) == [0xFF] 163 | expect([0xFF,0xFF].ensureSingleLeadingOneBit()) == [0xFF] 164 | expect([0xFF,0xFF,0x00].ensureSingleLeadingOneBit()) == [0xFF,0x00] 165 | expect([0x80].ensureSingleLeadingOneBit()) == [0x80] 166 | expect([0x40].ensureSingleLeadingOneBit()) == [0xFF,0x40] 167 | } 168 | } 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /SelfSignedCertTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SelfSignedCertTests/OIDTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Quick 4 | import Nimble 5 | @testable import SelfSignedCert 6 | 7 | class OIDTests: QuickSpec { 8 | 9 | override func spec() { 10 | 11 | it("supports equals") { 12 | let oid1 = OID(components: [1, 2, 3, 4]) 13 | let oid2 = OID(components: [1, 2, 3, 4]) 14 | expect(oid1) == oid2 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SelfSignedCertTests/SecIdentity+SelfSignedTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Stefan van den Oord. All rights reserved. 2 | 3 | import Quick 4 | import Nimble 5 | @testable import SelfSignedCert 6 | 7 | class SelfSignedCertTests: QuickSpec { 8 | 9 | override func spec() { 10 | 11 | it("Can create a self-signed identity") { 12 | let identity = SecIdentity.create(subjectCommonName: "test", subjectEmailAddress: "test@example.com") 13 | expect(identity).toNot(beNil()) 14 | } 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /SelfSignedCertTests/certdata.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svdo/swift-SelfSignedCert/23913d07d70697004edeb48cd5e1b293b05d5861/SelfSignedCertTests/certdata.der -------------------------------------------------------------------------------- /SelfSignedCertTests/pubkey.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svdo/swift-SelfSignedCert/23913d07d70697004edeb48cd5e1b293b05d5861/SelfSignedCertTests/pubkey.bin -------------------------------------------------------------------------------- /TestHost/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | var window: UIWindow? 6 | } 7 | 8 | -------------------------------------------------------------------------------- /TestHost/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /TestHost/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TestHost/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /TestHost/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TestHost/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TestHost/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class ViewController: UIViewController { 4 | } 5 | --------------------------------------------------------------------------------