├── LICENSE ├── README.md ├── images ├── t2s-1.png ├── t2s-2.png └── t2s-3.png ├── touch2sudo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── touch2sudo └── main.m /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, NVIDIA Corporation 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # touch2sudo 6 | 7 |

8 | 9 |

10 | 11 | `touch2sudo` is a standalone program if executed authenticates the user either through Touch ID or password. A successful authentication (confirmation) is signaled by a zero exit status from touch2sudo program. 12 | To authenticate sudo commands, we configure touch2sudo as `SSH_ASKPASS` confirmation program, invoked by ssh-agent. 13 | 14 | Infact this program can be used for any application that requires user authentication on Mac 15 | 16 | ## Mac configuration 17 | 18 | *Fingerprint authentication is done locally on Mac, but it acts as a gating mechanism for remote sudo authentication.* 19 | 20 | If you haven't setup Touch ID, you can find the instructions from Apple [here](https://support.apple.com/en-us/HT207054) 21 | 22 | ## touch2sudo installation 23 | 24 | You have two options: 25 | * Install `touch2sudo` binary using `brew` (OR) 26 | * Build from source 27 | 28 | ### Install using brew 29 | 30 | ```sh 31 | brew tap prbinu/touch2sudo 32 | brew install touch2sudo 33 | ``` 34 | 35 | ### Build from source 36 | 37 | ```sh 38 | git clone https://github.com/prbinu/touch2sudo 39 | ``` 40 | 41 | **Steps** 42 | 43 | 1. Open `touch2sudo.xcodeproj` file using [Xcode](https://developer.apple.com/xcode/) 44 | 45 | 2. Build: (*Product -> Build*) If the build is successful, you may see this dialog: 46 | 47 |

48 | 49 |

50 | 51 | 52 | 3. Archive: (*Product -> Archive -> Distribute Content -> Build Products -> Next -> Save*) Save the archive folder. The touch2sudo executable will be in the `/Product/usr/local/bin` path. 53 | 54 | 4. Install: Copy `touch2sudo` binary to `/usr/local/bin` 55 | 56 | 5. Run: `touch2sudo` 57 | 58 | 59 | ## Configure ssh-agent with touch2sudo 60 | 61 | Generate a new SSH key pair for sudo: 62 | 63 | ```sh 64 | $ ssh-keygen -t rsa -b 2048 65 | Generating public/private rsa key pair. 66 | Enter file in which to save the key (/Users/binu/.ssh/id_rsa): /Users/binu/.ssh/id_rsa_sudo 67 | Enter passphrase (empty for no passphrase): 68 | Enter same passphrase again: 69 | Your identification has been saved in /Users/binu/.ssh/id_rsa_sudo. 70 | Your public key has been saved in /Users/binu/.ssh/id_rsa_sudo.pub. 71 | The key fingerprint is: 72 | SHA256:6Vf0p0iUzQaiXqjQlUU+BYeTGiQqzUeC7z7iBNg7alE binu@localhostThe key's randomart image is: 73 | + - -[RSA 2048] - - + 74 | | .. o.o+=++ | 75 | | .o = oo+++ = | 76 | | ..= o oo+.+ + | 77 | |.. E.o o.o + o | 78 | |o o. . S o . .| 79 | | o .. . o . o | 80 | | =. . . . . | 81 | | +..o . | 82 | |o… . | 83 | + - - [SHA256] - - -+ 84 | ``` 85 | 86 | Start `ssh-agent` 87 | 88 | ```sh 89 | $ export SSH_ASKPASS=/usr/local/bin/touch2sudo 90 | $ export DISPLAY=0 91 | $ eval $(ssh-agent) 92 | Agent pid 51863 93 | 94 | $ ssh-add -L 95 | The agent has no identities. 96 | 97 | $ env | grep SSH 98 | SSH_AGENT_PID=51863 99 | SSH_AUTH_SOCK=/var/folders/hm/x1_38yz53td1jty5xgs39dxm2lm58d/T//ssh-JssXsflTuHrC/agent.51862 100 | SSH_ASKPASS=/usr/local/bin/touch2sudo 101 | 102 | $ ssh-add -c id_rsa_sudo 103 | Identity added: id_rsa_sudo (binu-sudo@binu.local) 104 | The user must confirm each use of the key 105 | ``` 106 | 107 | To make it work, on remote server you need to configure `pam-ssh-agent-auth` - a PAM module that does SSH key authentication for sudo. 108 | pam-ssh-agent-auth is based on SSH *agent-forwarding* feature that allow the PAM module to authenticate sudo command using key cached in ssh-agent running on your workstation (Mac). 109 | 110 | **SSH Agent Forwarding Security** 111 | To avoid exposure of other keys in your local ssh-agent to the connecting host, you may a use a seperate SSH key (for sudo) with a dedicated `ssh-agent` for agent-forwarding. Use [`ForwardAgent`](https://man.openbsd.org/ssh_config#ForwardAgent) option to pass the path/env-var of this sudo ssh-agent. 112 | 113 | For the complete information on end to end setup, refer: 114 | https://medium.com/@prbinu/touch2sudo-enable-remote-sudo-two-factor-authentication-using-mac-touch-id-df638b7da594 115 | 116 | -------------------------------------------------------------------------------- /images/t2s-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-1.png -------------------------------------------------------------------------------- /images/t2s-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-2.png -------------------------------------------------------------------------------- /images/t2s-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prbinu/touch2sudo/11f643e34cd90b3764e0b34269449f5d682e5acd/images/t2s-3.png -------------------------------------------------------------------------------- /touch2sudo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2FC7505721D95A1E007B32AC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FC7505621D95A1E007B32AC /* main.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 2FC7505121D95A1E007B32AC /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 2FC7505321D95A1E007B32AC /* touch2sudo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = touch2sudo; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 2FC7505621D95A1E007B32AC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 2FC7505021D95A1E007B32AC /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 2FC7504A21D95A1E007B32AC = { 42 | isa = PBXGroup; 43 | children = ( 44 | 2FC7505521D95A1E007B32AC /* touch2sudo */, 45 | 2FC7505421D95A1E007B32AC /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | 2FC7505421D95A1E007B32AC /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 2FC7505321D95A1E007B32AC /* touch2sudo */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | 2FC7505521D95A1E007B32AC /* touch2sudo */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 2FC7505621D95A1E007B32AC /* main.m */, 61 | ); 62 | path = touch2sudo; 63 | sourceTree = ""; 64 | }; 65 | /* End PBXGroup section */ 66 | 67 | /* Begin PBXNativeTarget section */ 68 | 2FC7505221D95A1E007B32AC /* touch2sudo */ = { 69 | isa = PBXNativeTarget; 70 | buildConfigurationList = 2FC7505A21D95A1E007B32AC /* Build configuration list for PBXNativeTarget "touch2sudo" */; 71 | buildPhases = ( 72 | 2FC7504F21D95A1E007B32AC /* Sources */, 73 | 2FC7505021D95A1E007B32AC /* Frameworks */, 74 | 2FC7505121D95A1E007B32AC /* CopyFiles */, 75 | ); 76 | buildRules = ( 77 | ); 78 | dependencies = ( 79 | ); 80 | name = touch2sudo; 81 | productName = touch2sudo; 82 | productReference = 2FC7505321D95A1E007B32AC /* touch2sudo */; 83 | productType = "com.apple.product-type.tool"; 84 | }; 85 | /* End PBXNativeTarget section */ 86 | 87 | /* Begin PBXProject section */ 88 | 2FC7504B21D95A1E007B32AC /* Project object */ = { 89 | isa = PBXProject; 90 | attributes = { 91 | LastUpgradeCheck = 1010; 92 | ORGANIZATIONNAME = "Binu Ramakrishnan"; 93 | TargetAttributes = { 94 | 2FC7505221D95A1E007B32AC = { 95 | CreatedOnToolsVersion = 10.1; 96 | }; 97 | }; 98 | }; 99 | buildConfigurationList = 2FC7504E21D95A1E007B32AC /* Build configuration list for PBXProject "touch2sudo" */; 100 | compatibilityVersion = "Xcode 9.3"; 101 | developmentRegion = en; 102 | hasScannedForEncodings = 0; 103 | knownRegions = ( 104 | en, 105 | ); 106 | mainGroup = 2FC7504A21D95A1E007B32AC; 107 | productRefGroup = 2FC7505421D95A1E007B32AC /* Products */; 108 | projectDirPath = ""; 109 | projectRoot = ""; 110 | targets = ( 111 | 2FC7505221D95A1E007B32AC /* touch2sudo */, 112 | ); 113 | }; 114 | /* End PBXProject section */ 115 | 116 | /* Begin PBXSourcesBuildPhase section */ 117 | 2FC7504F21D95A1E007B32AC /* Sources */ = { 118 | isa = PBXSourcesBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | 2FC7505721D95A1E007B32AC /* main.m in Sources */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXSourcesBuildPhase section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | 2FC7505821D95A1E007B32AC /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | ALWAYS_SEARCH_USER_PATHS = NO; 132 | CLANG_ANALYZER_NONNULL = YES; 133 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 134 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 135 | CLANG_CXX_LIBRARY = "libc++"; 136 | CLANG_ENABLE_MODULES = YES; 137 | CLANG_ENABLE_OBJC_ARC = YES; 138 | CLANG_ENABLE_OBJC_WEAK = YES; 139 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 140 | CLANG_WARN_BOOL_CONVERSION = YES; 141 | CLANG_WARN_COMMA = YES; 142 | CLANG_WARN_CONSTANT_CONVERSION = YES; 143 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 144 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 145 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 146 | CLANG_WARN_EMPTY_BODY = YES; 147 | CLANG_WARN_ENUM_CONVERSION = YES; 148 | CLANG_WARN_INFINITE_RECURSION = YES; 149 | CLANG_WARN_INT_CONVERSION = YES; 150 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 151 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 152 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 153 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 154 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 155 | CLANG_WARN_STRICT_PROTOTYPES = YES; 156 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 157 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 158 | CLANG_WARN_UNREACHABLE_CODE = YES; 159 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 160 | CODE_SIGN_IDENTITY = "-"; 161 | COPY_PHASE_STRIP = NO; 162 | DEBUG_INFORMATION_FORMAT = dwarf; 163 | ENABLE_STRICT_OBJC_MSGSEND = YES; 164 | ENABLE_TESTABILITY = YES; 165 | GCC_C_LANGUAGE_STANDARD = gnu11; 166 | GCC_DYNAMIC_NO_PIC = NO; 167 | GCC_NO_COMMON_BLOCKS = YES; 168 | GCC_OPTIMIZATION_LEVEL = 0; 169 | GCC_PREPROCESSOR_DEFINITIONS = ( 170 | "DEBUG=1", 171 | "$(inherited)", 172 | ); 173 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 174 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 175 | GCC_WARN_UNDECLARED_SELECTOR = YES; 176 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 177 | GCC_WARN_UNUSED_FUNCTION = YES; 178 | GCC_WARN_UNUSED_VARIABLE = YES; 179 | MACOSX_DEPLOYMENT_TARGET = 10.13; 180 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 181 | MTL_FAST_MATH = YES; 182 | ONLY_ACTIVE_ARCH = YES; 183 | SDKROOT = macosx; 184 | }; 185 | name = Debug; 186 | }; 187 | 2FC7505921D95A1E007B32AC /* Release */ = { 188 | isa = XCBuildConfiguration; 189 | buildSettings = { 190 | ALWAYS_SEARCH_USER_PATHS = NO; 191 | CLANG_ANALYZER_NONNULL = YES; 192 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 193 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 194 | CLANG_CXX_LIBRARY = "libc++"; 195 | CLANG_ENABLE_MODULES = YES; 196 | CLANG_ENABLE_OBJC_ARC = YES; 197 | CLANG_ENABLE_OBJC_WEAK = YES; 198 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 199 | CLANG_WARN_BOOL_CONVERSION = YES; 200 | CLANG_WARN_COMMA = YES; 201 | CLANG_WARN_CONSTANT_CONVERSION = YES; 202 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 204 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 205 | CLANG_WARN_EMPTY_BODY = YES; 206 | CLANG_WARN_ENUM_CONVERSION = YES; 207 | CLANG_WARN_INFINITE_RECURSION = YES; 208 | CLANG_WARN_INT_CONVERSION = YES; 209 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 210 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 211 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 212 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 213 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 214 | CLANG_WARN_STRICT_PROTOTYPES = YES; 215 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 216 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 217 | CLANG_WARN_UNREACHABLE_CODE = YES; 218 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 219 | CODE_SIGN_IDENTITY = "-"; 220 | COPY_PHASE_STRIP = NO; 221 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 222 | ENABLE_NS_ASSERTIONS = NO; 223 | ENABLE_STRICT_OBJC_MSGSEND = YES; 224 | GCC_C_LANGUAGE_STANDARD = gnu11; 225 | GCC_NO_COMMON_BLOCKS = YES; 226 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 227 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 228 | GCC_WARN_UNDECLARED_SELECTOR = YES; 229 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 230 | GCC_WARN_UNUSED_FUNCTION = YES; 231 | GCC_WARN_UNUSED_VARIABLE = YES; 232 | MACOSX_DEPLOYMENT_TARGET = 10.13; 233 | MTL_ENABLE_DEBUG_INFO = NO; 234 | MTL_FAST_MATH = YES; 235 | SDKROOT = macosx; 236 | }; 237 | name = Release; 238 | }; 239 | 2FC7505B21D95A1E007B32AC /* Debug */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | CODE_SIGN_STYLE = Automatic; 243 | PRODUCT_NAME = "$(TARGET_NAME)"; 244 | }; 245 | name = Debug; 246 | }; 247 | 2FC7505C21D95A1E007B32AC /* Release */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | CODE_SIGN_STYLE = Automatic; 251 | PRODUCT_NAME = "$(TARGET_NAME)"; 252 | }; 253 | name = Release; 254 | }; 255 | /* End XCBuildConfiguration section */ 256 | 257 | /* Begin XCConfigurationList section */ 258 | 2FC7504E21D95A1E007B32AC /* Build configuration list for PBXProject "touch2sudo" */ = { 259 | isa = XCConfigurationList; 260 | buildConfigurations = ( 261 | 2FC7505821D95A1E007B32AC /* Debug */, 262 | 2FC7505921D95A1E007B32AC /* Release */, 263 | ); 264 | defaultConfigurationIsVisible = 0; 265 | defaultConfigurationName = Release; 266 | }; 267 | 2FC7505A21D95A1E007B32AC /* Build configuration list for PBXNativeTarget "touch2sudo" */ = { 268 | isa = XCConfigurationList; 269 | buildConfigurations = ( 270 | 2FC7505B21D95A1E007B32AC /* Debug */, 271 | 2FC7505C21D95A1E007B32AC /* Release */, 272 | ); 273 | defaultConfigurationIsVisible = 0; 274 | defaultConfigurationName = Release; 275 | }; 276 | /* End XCConfigurationList section */ 277 | }; 278 | rootObject = 2FC7504B21D95A1E007B32AC /* Project object */; 279 | } 280 | -------------------------------------------------------------------------------- /touch2sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /touch2sudo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // touch2sudo 4 | // 5 | // Created by Binu Ramakrishnan on 12/30/18. 6 | // Copyright (c) 2018 NVIDIA CORPORATION. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | int main(int argc, const char * argv[]) { 14 | @autoreleasepool { 15 | 16 | if ((argc == 2) && (strncmp(argv[1], "-h", strlen("-h")) == 0)) { 17 | printf("Usage: touch2sudo -reason \n"); 18 | printf(" -reason The app-provided reason for requesting authentication,\n"); 19 | printf(" which displays in the authentication dialog presented to the user\n"); 20 | printf(" -h Help!\n"); 21 | return 1; 22 | } 23 | NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults]; 24 | NSString *reason = ([standardDefaults stringForKey:@"reason"] != NULL) ? 25 | [standardDefaults stringForKey:@"reason"]: @"perform an action that requires authentication"; 26 | 27 | // SSH_ASKPASS format 28 | if (([standardDefaults stringForKey:@"reason"] == NULL) && (argc == 2)) { 29 | NSString *arg = [NSString stringWithUTF8String: argv[1]]; 30 | NSArray *listItems = [arg componentsSeparatedByString:@"Key fingerprint "]; 31 | if ((listItems.count == 2) && ([listItems[1] hasPrefix:@"SHA256:"])) { 32 | reason = [reason stringByAppendingString:@"\n\n"]; 33 | reason = [reason stringByAppendingString:listItems[0]]; 34 | reason = [reason stringByAppendingString:@"\n\nKey fingerprint: "]; 35 | reason = [reason stringByAppendingString:listItems[1]]; 36 | } 37 | } 38 | 39 | __block int result = 1; 40 | LAContext *context = [[LAContext alloc] init]; 41 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 42 | [context evaluatePolicy: kLAPolicyDeviceOwnerAuthentication localizedReason: reason 43 | reply:^(BOOL success, NSError * _Nullable error) { 44 | if (success) { 45 | result = 0; 46 | } 47 | else { 48 | NSLog(@"%s\n", error.localizedDescription.UTF8String); 49 | result = 1; 50 | } 51 | 52 | dispatch_semaphore_signal(semaphore); 53 | }]; 54 | 55 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 56 | return result; 57 | } 58 | } 59 | 60 | --------------------------------------------------------------------------------