From 5ce3239edb763bf278896e66aeb96ddd72dff04a Mon Sep 17 00:00:00 2001 From: kevinzhow Date: Mon, 15 Jan 2024 21:29:40 +0900 Subject: [PATCH 1/5] Use CryptoSwift to perform the sign --- Package.swift | 2 +- Sources/OAuth1/Connection.swift | 2 +- .../ServiceAccountTokenProvider/RSA.swift | 34 ++++++------------- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/Package.swift b/Package.swift index 035adfe..bceb09c 100644 --- a/Package.swift +++ b/Package.swift @@ -29,7 +29,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", from: "2.59.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", "1.1.3"..."1.3.2"), + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.8.1"), .package(url: "https://github.com/attaswift/BigInt", from: "5.0.0"), ], targets: [ diff --git a/Sources/OAuth1/Connection.swift b/Sources/OAuth1/Connection.swift index 88e4d74..4b16e0a 100644 --- a/Sources/OAuth1/Connection.swift +++ b/Sources/OAuth1/Connection.swift @@ -49,7 +49,7 @@ public class Connection { // generate the signature let hmac = try! CryptoSwift.HMAC(key: secret, variant: .sha1).authenticate(Array(signatureBaseString.utf8)) - parameters["oauth_signature"] = hmac.toBase64()! + parameters["oauth_signature"] = hmac.toBase64() } public class func performRequest( diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift b/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift index 4e629bf..73d392e 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift @@ -14,11 +14,14 @@ import Foundation import BigInt +import CryptoSwift struct RSAKey { - var N : BigUInt - var E : BigUInt - var D : BigUInt + var N : BigUInteger + var E : BigUInteger + var D : BigUInteger + var rsa: RSA + /* var Primes : [BigUInt] var Dp: BigUInt @@ -35,31 +38,16 @@ struct RSAKey { } if let der = Data(base64Encoded: pem, options: []), let asn1Array = ASN1Decoder.decode(der: der) { - N = BigUInt(asn1Array[2].children?[1].data ?? Data()) - E = BigUInt(asn1Array[2].children?[2].data ?? Data()) - D = BigUInt(asn1Array[2].children?[3].data ?? Data()) + N = BigUInteger(asn1Array[2].children?[1].data ?? Data()) + E = BigUInteger(asn1Array[2].children?[2].data ?? Data()) + D = BigUInteger(asn1Array[2].children?[3].data ?? Data()) + rsa = RSA(n: N, e: E, d: D) } else { return nil } } func sign(hash:[UInt8]) -> [UInt8] { - let prefix : [UInt8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20] - var dataToEncode = [UInt8](repeating: 0xFF, count: 256) - dataToEncode[0] = 0x00 - dataToEncode[1] = 0x01 - let offset1 = 256 - hash.count - prefix.count - dataToEncode[offset1 - 1] = 0x00 - for i in 0.. Date: Mon, 15 Jan 2024 21:40:40 +0900 Subject: [PATCH 2/5] fix sign logic --- Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift | 4 +--- Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift b/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift index 6d12a04..bccf785 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift @@ -51,9 +51,7 @@ struct JWT { let claims = SwiftyBase64.EncodeString(Array(claimsData), alphabet:.URLAndFilenameSafe) let body = header + "." + claims let bodyData = body.data(using: String.Encoding.utf8)! - let sha2 = SHA2(variant: SHA2.Variant(rawValue:256)!) - let hash = sha2.calculate(for:Array(bodyData)) - let signature = rsaKey.sign(hash:hash) + let signature = rsaKey.sign(bytes: Array(bodyData)) let signatureString = SwiftyBase64.EncodeString(signature, alphabet:.URLAndFilenameSafe) return body + "." + signatureString } diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift b/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift index 73d392e..9314b18 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift @@ -47,7 +47,7 @@ struct RSAKey { } } - func sign(hash:[UInt8]) -> [UInt8] { - return try! rsa.sign(hash) + func sign(bytes:[UInt8]) -> [UInt8] { + return try! rsa.sign(bytes) } } From 533f421a789c02eb203ea657cf04006f1208046f Mon Sep 17 00:00:00 2001 From: kevinzhow Date: Mon, 15 Jan 2024 22:05:14 +0900 Subject: [PATCH 3/5] feat: use JWTKit to perform the sign --- Package.swift | 22 +++++--- .../ServiceAccountTokenProvider/JWT.swift | 4 +- .../ServiceAccountTokenProvider/RSA.swift | 53 ------------------- .../ServiceAccountTokenProvider.swift | 3 +- 4 files changed, 21 insertions(+), 61 deletions(-) delete mode 100644 Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift diff --git a/Package.swift b/Package.swift index bceb09c..47fd134 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.1 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ import PackageDescription let package = Package( name: "Auth", platforms: [ - .macOS(.v10_12), .iOS(.v9), .tvOS(.v9) + .macOS(.v10_15), .iOS(.v9), .tvOS(.v9) ], products: [ .library(name: "OAuth1", targets: ["OAuth1"]), @@ -30,16 +30,26 @@ let package = Package( dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", from: "2.59.0"), .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.8.1"), - .package(url: "https://github.com/attaswift/BigInt", from: "5.0.0"), + .package(url: "https://github.com/attaswift/BigInt.git", from: "5.0.0"), + .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0"), ], targets: [ .target(name: "OAuth1", - dependencies: ["CryptoSwift", "TinyHTTPServer"]), + dependencies: [ + .product(name: "CryptoSwift", package: "CryptoSwift"), + "TinyHTTPServer" + ]), .target(name: "OAuth2", - dependencies: ["CryptoSwift", "TinyHTTPServer", "BigInt", "SwiftyBase64"], + dependencies: [.product(name: "CryptoSwift", package: "CryptoSwift"), + "TinyHTTPServer", + .product(name: "BigInt", package: "BigInt"), + "SwiftyBase64", + .product(name: "JWTKit", package: "jwt-kit") + ], exclude: ["FCMTokenProvider"]), .target(name: "TinyHTTPServer", - dependencies: ["NIO", "NIOHTTP1"]), + dependencies: [.product(name: "NIO" , package: "swift-nio"), + .product(name: "NIOHTTP1" , package: "swift-nio")]), .target(name: "SwiftyBase64"), .target(name: "TokenSource", dependencies: ["OAuth2"], path: "Sources/Examples/TokenSource"), .target(name: "Google", dependencies: ["OAuth2"], path: "Sources/Examples/Google"), diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift b/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift index bccf785..f7ffef7 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/JWT.swift @@ -15,6 +15,7 @@ import Foundation import CryptoSwift import SwiftyBase64 +import JWTKit struct JWTHeader : Codable { let Algorithm : String @@ -51,7 +52,8 @@ struct JWT { let claims = SwiftyBase64.EncodeString(Array(claimsData), alphabet:.URLAndFilenameSafe) let body = header + "." + claims let bodyData = body.data(using: String.Encoding.utf8)! - let signature = rsaKey.sign(bytes: Array(bodyData)) + let signer = JWTSigner.rs256(key: rsaKey) + let signature = try signer.algorithm.sign(bodyData) let signatureString = SwiftyBase64.EncodeString(signature, alphabet:.URLAndFilenameSafe) return body + "." + signatureString } diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift b/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift deleted file mode 100644 index 9314b18..0000000 --- a/Sources/OAuth2/ServiceAccountTokenProvider/RSA.swift +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation -import BigInt -import CryptoSwift - -struct RSAKey { - var N : BigUInteger - var E : BigUInteger - var D : BigUInteger - var rsa: RSA - - /* - var Primes : [BigUInt] - var Dp: BigUInt - var Dq: BigUInt - var Qinv : BigUInt - */ - - init?(privateKey:String) { - var pem = "" - for line in privateKey.components(separatedBy:"\n") { - if line.range(of:"PRIVATE KEY") == nil { - pem += line - } - } - if let der = Data(base64Encoded: pem, options: []), - let asn1Array = ASN1Decoder.decode(der: der) { - N = BigUInteger(asn1Array[2].children?[1].data ?? Data()) - E = BigUInteger(asn1Array[2].children?[2].data ?? Data()) - D = BigUInteger(asn1Array[2].children?[3].data ?? Data()) - rsa = RSA(n: N, e: E, d: D) - } else { - return nil - } - } - - func sign(bytes:[UInt8]) -> [UInt8] { - return try! rsa.sign(bytes) - } -} diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift b/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift index 558cb71..44ab353 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift @@ -16,6 +16,7 @@ import Foundation #if canImport(FoundationNetworking) import FoundationNetworking #endif +import JWTKit struct ServiceAccountCredentials : Codable { let CredentialType : String @@ -58,7 +59,7 @@ public class ServiceAccountTokenProvider : TokenProvider { } self.credentials = credentials self.scopes = scopes - guard let rsaKey = RSAKey(privateKey:credentials.PrivateKey) + guard let rsaKey = try? RSAKey.private(pem: credentials.PrivateKey) else { return nil } From 8ddb82a95194f25f3fbad78cb070c534c6c3a7b4 Mon Sep 17 00:00:00 2001 From: kevinzhow Date: Mon, 15 Jan 2024 22:15:41 +0900 Subject: [PATCH 4/5] Update swift.yml --- .github/workflows/swift.yml | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index c188d2c..5079c6d 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -2,27 +2,22 @@ name: Swift on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: - build-ubuntu: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Swift - run: | - SWIFT_URL=https://swift.org/builds/swift-5.1.1-release/ubuntu1404/swift-5.1.1-RELEASE/swift-5.1.1-RELEASE-ubuntu14.04.tar.gz - curl -fSsL $SWIFT_URL -o swift.tar.gz - sudo tar -xzf swift.tar.gz --strip-components=2 --directory=/usr/local - which swift - - name: Build - run: | - swift package -v resolve - make all + - name: Checkout + uses: actions/checkout@v3 + - name: Install swift version + uses: swift-actions/setup-swift@v1 + - name: Build + run: | + swift package -v resolve + make all build-macos: runs-on: macOS-latest From 4bc23e9ade8f764bcf36f7ebb840aade3978369b Mon Sep 17 00:00:00 2001 From: kevinzhow Date: Mon, 15 Jan 2024 22:18:27 +0900 Subject: [PATCH 5/5] fix: format --- .../ServiceAccountTokenProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift b/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift index 44ab353..1d610a5 100644 --- a/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift +++ b/Sources/OAuth2/ServiceAccountTokenProvider/ServiceAccountTokenProvider.swift @@ -59,7 +59,7 @@ public class ServiceAccountTokenProvider : TokenProvider { } self.credentials = credentials self.scopes = scopes - guard let rsaKey = try? RSAKey.private(pem: credentials.PrivateKey) + guard let rsaKey = try? RSAKey.private(pem: credentials.PrivateKey) else { return nil }