Compare commits

...

13 Commits

Author SHA1 Message Date
8bbf489146 Relaunch agent if updated (#86) 2020-04-04 15:16:31 -07:00
30148ee3a4 Revert "Xcode 11.4 changes"
This reverts commit c306801149.
2020-04-03 00:44:13 -07:00
c306801149 Xcode 11.4 changes 2020-04-02 18:22:59 -07:00
9c60a0b7dd Merge branch 'master' of github.com:maxgoedjen/secretive 2020-04-02 00:54:14 -07:00
5b38ef00c1 Fix #84 2020-04-02 00:53:55 -07:00
ccbf92785d Fix padding bug (#83) 2020-04-02 00:43:45 -07:00
f1e8e43f62 Update FAQ.md 2020-04-01 22:11:45 -07:00
7b1563f167 Update FAQ.md 2020-03-31 23:11:04 -07:00
cca070dbe4 Update FAQ.md 2020-03-30 23:44:38 -07:00
31e51e45c1 Move types to common (#81) 2020-03-29 17:26:43 -07:00
4bfb3a0012 Rephrase access control. 2020-03-28 18:08:54 -07:00
a0ed880386 Fix #80. 2020-03-27 19:24:37 -07:00
92b9648e04 FAQ (#76) 2020-03-25 23:35:02 -07:00
11 changed files with 143 additions and 16 deletions

37
FAQ.md Normal file
View File

@ -0,0 +1,37 @@
# FAQ
### How do I import my current SSH keys, or export my Secretive Keys?
The secure enclave doesn't allow import or export of private keys. For any new computer, you should just create a new set of keys. If you're using a smart card, you _might_ be able to export your private key from the vendor's software.
### Secretive doesn't work with my git client
Secretive relies on the `SSH_AUTH_SOCK` environment variable being respected. The `git` and `ssh` command line tools natively respect this, but third party apps may require some configuration to work. A non-exhaustive list of clients is provided here:
Tower - [Instructions](https://www.git-tower.com/help/mac/integration/environment)
GitHub Desktop: Should just work, no configuration needed
### Secretive isn't working for me
Please run `ssh -Tv git@github.com` in your terminal and paste the output in a [new GitHub issue](https://github.com/maxgoedjen/secretive/issues/new) with a description of your issue.
### Why should I trust you?
You shouldn't, for a piece of software like this. Secretive, by design, has an auditable build process. Each build has a fully auditable build log, showing the source it was built from and a SHA of the build product. You can check the SHA of the zip you download against the SHA output in the build log (which is linked in the About window).
### I want to build Secretive from source
Awesome! Just bear in mind that because an app only has access to the keychain items that it created, if you have secrets that you created with the prebuilt version of Secretive, you'll be unable to access them using your own custom build (since you'll have changed the bundled ID).
### I have a security issue
Please contact [max.goedjen@gmail.com](mailto:max.goedjen@gmail.com) with a subject containing "SECRETIVE SECURITY" immediately with details, and I'll address the issue and credit you ASAP.
### I have a non-security related bug
Please file a [GitHub issue](https://github.com/maxgoedjen/secretive/issues/new) for it. I will not provide email support with the exception of the critical security issues mentioned above.
### I want to contribute to Secretive
Sweet! Please check out the [contributing guidelines](CONTRIBUTING.md) and go from there.

View File

@ -14,7 +14,7 @@ The most common setup for SSH keys is just keeping them on disk, guarded by prop
### Access Control
If your Mac has a Secure Enclave, it also has support for strong biometric access controls like Touch ID. You can configure your key so that they require Touch ID (or Watch) authentication before they're accessed.
If your Mac has a Secure Enclave, it also has support for strong access controls like Touch ID, or authentication with Apple Watch. You can configure your key so that they require Touch ID (or Watch) authentication before they're accessed.
<img src="/.github/readme/touchid.png" alt="Screenshot of Secretive authenticating with Touch ID">
@ -30,13 +30,9 @@ For Macs without Secure Enclaves, you can configure a Smart Card (such as a Yubi
## Getting Started
### Setup for Third Party Apps
When you first launch Secretive, you'll be prompted to set up your command line environment. You can redisplay this prompt at any time by going to `Menu > Help -> Set Up Helper App`.
For non-command-line based apps, like GUI Git clients, you may need to go through app-specific setup.
[Tower](https://www.git-tower.com/help/mac/integration/environment)
### FAQ
There's a [FAQ here](FAQ.md).
### Auditable Build Process
@ -52,4 +48,4 @@ Beacuse secrets in the Secure Enclave are not exportable, they are not able to b
## Security
If you discover any vulnerabilities in this project, please notify max.goedjen@gmail.com
If you discover any vulnerabilities in this project, please notify [max.goedjen@gmail.com](mailto:max.goedjen@gmail.com) with the subject containing "SECRETIVE SECURITY."

View File

@ -113,8 +113,17 @@ extension Agent {
let rawLength = rawRepresentation.count/2
let r = rawRepresentation[0..<rawLength]
let s = rawRepresentation[rawLength...]
// Check if we need to pad with 0x00 to prevent certain
// ssh servers from thinking r or s is negative
let paddingRange: ClosedRange<UInt8> = 0x80...0xFF
var r = Data(rawRepresentation[0..<rawLength])
if paddingRange ~= r.first! {
r.insert(0x00, at: 0)
}
var s = Data(rawRepresentation[rawLength...])
if paddingRange ~= s.first! {
s.insert(0x00, at: 0)
}
var signatureChunk = Data()
signatureChunk.append(writer.lengthAndData(of: r))

View File

@ -49,8 +49,15 @@ class AgentTests: XCTestCase {
_ = inner.readNextChunk()
let signedData = inner.readNextChunk()
let rsData = OpenSSHReader(data: signedData)
let r = rsData.readNextChunk()
let s = rsData.readNextChunk()
var r = rsData.readNextChunk()
var s = rsData.readNextChunk()
// This is fine IRL, but it freaks out CryptoKit
if r[0] == 0 {
r.removeFirst()
}
if s[0] == 0 {
s.removeFirst()
}
var rs = r
rs.append(s)
let signature = try! P256.Signing.ECDSASignature(rawRepresentation: rs)

View File

@ -10,6 +10,8 @@
50020BB024064869003D4025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50020BAF24064869003D4025 /* AppDelegate.swift */; };
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; };
50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; };
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; };
50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* AppDelegate.swift */; };
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; };
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
@ -206,6 +208,8 @@
50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSHWriterTests.swift; sourceTree = "<group>"; };
50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = "<group>"; };
50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = "<group>"; };
50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; };
50617D8223FCE48E0099B055 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -346,6 +350,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
504BA92D243171F20064740E /* Types */ = {
isa = PBXGroup;
children = (
50617DCA23FCECA10099B055 /* Secret.swift */,
50617DC623FCE4EA0099B055 /* SecretStore.swift */,
);
path = Types;
sourceTree = "<group>";
};
50617D7623FCE48D0099B055 = {
isa = PBXGroup;
children = (
@ -418,8 +431,6 @@
isa = PBXGroup;
children = (
50617DAA23FCE4AB0099B055 /* SecretKit.h */,
50617DCA23FCECA10099B055 /* Secret.swift */,
50617DC623FCE4EA0099B055 /* SecretStore.swift */,
5099A02C23FE56D70062B6F2 /* Common */,
50617DCC23FCECEE0099B055 /* SecureEnclave */,
5099A02523FE34DE0062B6F2 /* SmartCard */,
@ -505,6 +516,8 @@
isa = PBXGroup;
children = (
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */,
50571E0424393D1500F76F6C /* LaunchAgentController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -522,6 +535,7 @@
5099A02C23FE56D70062B6F2 /* Common */ = {
isa = PBXGroup;
children = (
504BA92D243171F20064740E /* Types */,
5068389F2415EA4F00F55094 /* Erasers */,
506838A42415EA6800F55094 /* OpenSSH */,
5068389D241471CD00F55094 /* SecretStoreList.swift */,
@ -908,10 +922,12 @@
files = (
50C385A9240B636500AF2719 /* SetupView.swift in Sources */,
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */,
50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */,
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */,
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */,
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */,
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */,
50731669241E00C20023809E /* NoticeView.swift in Sources */,

View File

@ -17,6 +17,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}()
let updater = Updater()
let agentStatusChecker = AgentStatusChecker()
let justUpdatedChecker = JustUpdatedChecker()
func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = ContentView(storeList: storeList, updater: updater, agentStatusChecker: agentStatusChecker, runSetupBlock: { self.runSetup(sender: nil) })
@ -40,6 +41,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
newMenuItem.isEnabled = true
}
runSetupIfNeeded()
relaunchAgentIfNeeded()
}
func applicationDidBecomeActive(_ notification: Notification) {
@ -89,6 +91,12 @@ extension AppDelegate {
}
}
func relaunchAgentIfNeeded() {
if agentStatusChecker.running && justUpdatedChecker.justUpdated {
LaunchAgentController().relaunch()
}
}
}
extension AppDelegate {

View File

@ -0,0 +1,36 @@
import Foundation
import Combine
import AppKit
protocol JustUpdatedCheckerProtocol: ObservableObject {
var justUpdated: Bool { get }
}
class JustUpdatedChecker: ObservableObject, JustUpdatedCheckerProtocol {
@Published var justUpdated: Bool = false
init() {
check()
}
func check() {
let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String ?? "None"
let currentBuild = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
UserDefaults.standard.set(currentBuild, forKey: Constants.previousVersionUserDefaultsKey)
if lastBuild != currentBuild {
justUpdated = true
}
}
}
extension JustUpdatedChecker {
enum Constants {
static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild"
}
}

View File

@ -0,0 +1,19 @@
import Foundation
import ServiceManagement
struct LaunchAgentController {
func install() -> Bool {
setEnabled(true)
}
func relaunch() {
_ = setEnabled(false)
_ = setEnabled(true)
}
private func setEnabled(_ enabled: Bool) -> Bool {
SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, enabled)
}
}

View File

@ -1,6 +1,5 @@
import Foundation
import SwiftUI
import ServiceManagement
struct SetupView: View {
@ -117,7 +116,7 @@ struct SetupStepCommandView: View {
extension SetupView {
func installLaunchAgent() -> Bool {
SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, true)
LaunchAgentController().install()
}
func markAsDone() -> Bool {