2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Foundation/Foundation.h>
25 #import <objc/runtime.h>
26 #import <Foundation/NSXPCConnection_Private.h>
28 #import <utilities/debugging.h>
29 #import <Security/SecEntitlements.h>
30 #import "keychain/ot/OctagonControlServer.h"
31 #import "keychain/ot/OTManager.h"
32 #import "keychain/ot/OT.h"
33 #import "keychain/ot/OTConstants.h"
34 #import "keychain/categories/NSError+UsefulConstructors.h"
37 @interface OctagonXPCEntitlementChecker ()
38 @property OTManager* manager;
39 @property id<OctagonEntitlementBearerProtocol> entitlementBearer;
40 - (instancetype)initWithManager:(OTManager*)manager
41 entitlementBearer:(id<OctagonEntitlementBearerProtocol>)bearer;
44 @implementation OctagonXPCEntitlementChecker
46 - (instancetype)initWithManager:(OTManager*)manager entitlementBearer:(id<OctagonEntitlementBearerProtocol>)bearer
48 // NSProxy does not implement init, so don't call super init
50 _entitlementBearer = bearer;
54 - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
56 return [self.manager methodSignatureForSelector:selector];
59 - (void)forwardInvocation:(NSInvocation *)invocation
61 if(sel_isEqual(invocation.selector, @selector(fetchEscrowContents:contextID:reply:))) {
62 if(![self.entitlementBearer valueForEntitlement:kSecEntitlementPrivateOctagonEscrow]) {
63 secerror("Client %@ does not have entitlement %@, rejecting rpc", self.entitlementBearer, kSecEntitlementPrivateOctagonEscrow);
64 [invocation setSelector:@selector(failFetchEscrowContents:contextID:reply:)];
65 [invocation invokeWithTarget:self];
69 [invocation invokeWithTarget:self.manager];
72 - (void)failFetchEscrowContents:(NSString*)containerName
73 contextID:(NSString *)contextID
74 reply:(void (^)(NSData* _Nullable entropy,
75 NSString* _Nullable bottleID,
76 NSData* _Nullable signingPublicKey,
77 NSError* _Nullable error))reply
79 reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain
80 code:errSecMissingEntitlement
81 description:[NSString stringWithFormat: @"Missing entitlement '%@'", kSecEntitlementPrivateOctagonEscrow]]);
84 + (BOOL)conformsToProtocol:(Protocol *)protocol {
85 return [[OTManager class] conformsToProtocol:protocol];
88 // Launder a OctagonXPCEntitlementChecker into something that type-safely implements the protocol we're interested in
89 + (id<OTControlProtocol>)createWithManager:(OTManager*)manager
90 entitlementBearer:(id<OctagonEntitlementBearerProtocol>)bearer
92 return (id<OTControlProtocol>) [[OctagonXPCEntitlementChecker alloc] initWithManager:manager entitlementBearer:bearer];
97 @interface OctagonControlServer : NSObject <NSXPCListenerDelegate>
100 @implementation OctagonControlServer
102 - (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
105 NSNumber *num = [newConnection valueForEntitlement:kSecEntitlementPrivateOctagon];
106 if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) {
107 secerror("octagon: Client pid: %d doesn't have entitlement: %@",
108 [newConnection processIdentifier], kSecEntitlementPrivateOctagon);
111 // In the future, we should consider vending a proxy object that can return a nicer error.
112 if (!OctagonIsEnabled()) {
113 secerror("Octagon: Client pid: %d attempted to use Octagon, but Octagon is not enabled.",
114 newConnection.processIdentifier);
118 secinfo("octagon", "received connection from client pid %d", [newConnection processIdentifier]);
119 newConnection.exportedInterface = OTSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(OTControlProtocol)]);
120 newConnection.exportedObject = [OctagonXPCEntitlementChecker createWithManager:[OTManager manager] entitlementBearer:newConnection];
122 [newConnection resume];
126 secerror("octagon does not exist on this platform");
133 OctagonControlServerInitialize(void)
135 static dispatch_once_t once;
136 static OctagonControlServer *server;
137 static NSXPCListener *listener;
139 dispatch_once(&once, ^{
141 server = [OctagonControlServer new];
143 listener = [[NSXPCListener alloc] initWithMachServiceName:@(kSecuritydOctagonServiceName)];
144 listener.delegate = server;