├── .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 | 
9 | [](https://cocoapods.org/pods/SelfSignedCert)
10 | [](LICENSE.txt)
11 | 
12 | [](https://github.com/Carthage/Carthage)
13 | [](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 |
--------------------------------------------------------------------------------