Re: Security with Streams

2016-06-27 Thread Jens Alfke

> On Jun 26, 2016, at 11:30 PM, Gerriet M. Denkmann  
> wrote:
> 
> Could it, instead of getting the SecIdentityRef from the keychain, just use 
> MyServerCertificate.cer instead?

Nope. The server has to have a SecIdentityRef, because its side of the SSL 
handshake requires using the private key to sign data.

> And then the client would compare the certificate it receives with 
> MyServerCertificate.cer and notice that these are different, thus closing the 
> connection. (Correct ?)

If you’ve programmed the client to do that, yes.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Gerriet M. Denkmann

> On 27 Jun 2016, at 12:57, Jens Alfke  wrote:
> 
>> On Jun 26, 2016, at 8:13 PM, Gerriet M. Denkmann  
>> wrote:
>> 
>> Assume that an evil entity has got hold of “MyServerCertificate.cer”, but 
>> has no access to my keychain and thus to the private key of 
>> MyServerCertificate. 
>> Could they use this certificate to open a secure stream to a client? Or do 
>> they need the private key to sign?
> 
> — Servers don’t open connections to clients; it’s the other way around.

Sorry, I was speaking rather too loosely.

I meant: when the server accepts a connection from a client via 
netService:didAcceptConnectionWithInputStream:outputStream: 
it does:
[ inputStream setProperty: settings  forKey: kCFStreamPropertySSLSettings ]

where settings has: kCFStreamSSLCertificates = array with a SecIdentityRef 
obtained via SecItemCopyMatching().

Could it, instead of getting the SecIdentityRef from the keychain, just use 
MyServerCertificate.cer instead?


> — A certificate contains only the public key, not the private key. It can’t 
> be used to sign anything, only to verify signatures.

So this probably answers my question: It could not. (Correct ?).

So the evil server has to use its own EvilServerCertificate from its own 
keychain. 
And then the client would compare the certificate it receives with 
MyServerCertificate.cer and notice that these are different, thus closing the 
connection. (Correct ?)


Kind regards,

Gerriet.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Jens Alfke

> On Jun 26, 2016, at 8:13 PM, Gerriet M. Denkmann  wrote:
> 
> Assume that an evil entity has got hold of “MyServerCertificate.cer”, but has 
> no access to my keychain and thus to the private key of MyServerCertificate. 
> Could they use this certificate to open a secure stream to a client? Or do 
> they need the private key to sign?

— Servers don’t open connections to clients; it’s the other way around.
— There’s nothing private about a certificate. In fact, an SSL server sends its 
certificate out to any client that connects to it, as part of the SSL handshake.
— A certificate contains only the public key, not the private key. It can’t be 
used to sign anything, only to verify signatures.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Keary Suska

> On Jun 26, 2016, at 9:13 PM, Gerriet M. Denkmann  wrote:
> 
>> 
>> 
>> Self-signed certificates can only offer encryption, but cannot offer trust 
>> because they are not verifiable. You can’t use the server certificate as a 
>> key since you pass that key out to anyone who wants it (in your app), and 
>> anyone who gets it can impersonate the server.
> 
> Assume that an evil entity has got hold of “MyServerCertificate.cer”, but has 
> no access to my keychain and thus to the private key of MyServerCertificate. 
> Could they use this certificate to open a secure stream to a client? Or do 
> they need the private key to sign?

To clarify, I was pointing out two weaknesses that come out of self-signed 
certificates, and in the latter case how comparing an embedded certificate/key 
with the server’s public certificate/key would not offer any security if it 
were self-signed, as you would be using the cert as a passcode that anyone can 
easily have. With a verifiable certificate you wouldn’t normally have these 
weaknesses and you get server verification (usually called “authentication”) as 
part of the SSL/TLS protocol so you don’t have to code for that case (though 
you may need to be explicit that you want certificate verification if it isn’t 
the default).

For the latter part of the question, in asymmetric encryption schemes, the 
private key is certainly needed to decrypt but does not authenticate. If you 
permit ad-hoc connections from the server to the client, the only way to 
authenticate the server would be by the server providing a client certificate 
and that being verified by a third-party. Even a self-signed client certificate 
does not provide authentication as it too is tantamount to using the 
certificate as a password that you give you to anyone who buys your app. Now, 
normally, the communications would still be encrypted and difficult to 
decipher, as long as you are comparing signed certificates, but if the 
certificate ever changes you now have to redistribute the new signed 
certificate.

I would also reiterate that when using SSL/TLS you don’t need to bother with 
key verification such as what ssh uses, since ssh uses those methods precisely 
because it does not rely on third party authentication so requires the client 
and server to agree that the connection is valid even though neither can 
actually guarantee that it is the case. This would be more similar to my 
peer-to-peer example, where trust is agreed upon before communication proceeds. 
SSL/TLS is also more robust in this case because the certificate can change at 
any time (which will periodically happen every 1-5 years anyway) but the server 
can still be correctly authenticated.

HTH,

Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Gerriet M. Denkmann

> On 26 Jun 2016, at 21:59, Keary Suska  wrote:
> 
> 
>> On Jun 25, 2016, at 8:44 PM, Gerriet M. Denkmann  
>> wrote:
>> 
>> Following TN2326 I created a (self signed) Certificate Authority and a 
>> Digital Identity called "MyServerId".
>> 
> 
> 
>>> We are now falling into the rabbit hole that is peer-to-peer trust & 
>>> identity. How is your server going to identify it so that a client will 
>>> know that it’s the server it expects? I don’t know whether you’ve given any 
>>> thought to this; the answer affects how you’d implement this part of the 
>>> app.
>> 
>> I have thought about this, but I am not at all sure that my thoughts are 
>> correct.
>> Currently (as indicated in the code above) my client has a copy of the real 
>> server certificate and compares it with the certificate obtained from its 
>> inputStream.
>> I am not sure whether putting the server certificate into the client is ok 
>> or a breach of security. 
>> 
>> That is: the client will accept any server which has signed with the server 
>> certificate.
> 
> Self-signed certificates can only offer encryption, but cannot offer trust 
> because they are not verifiable. You can’t use the server certificate as a 
> key since you pass that key out to anyone who wants it (in your app), and 
> anyone who gets it can impersonate the server.

Assume that an evil entity has got hold of “MyServerCertificate.cer”, but has 
no access to my keychain and thus to the private key of MyServerCertificate. 
Could they use this certificate to open a secure stream to a client? Or do they 
need the private key to sign?


> I am unclear to me whether you are after a client-server (i.e. all servers 
> are under your control) or peer-to-peer (i.e. every client is a server and 
> every server is a client)) model? 

There is just one server, which is under my control.


Kind regards,

Gerriet.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Gerriet M. Denkmann

> On 27 Jun 2016, at 06:11, Jens Alfke  wrote:
> 
>> On Jun 25, 2016, at 7:44 PM, Gerriet M. Denkmann  
>> wrote:
> 
>> Absolutely not sure whether the code above is correct, but it seems to be 
>> working.

> It’s fine; the certificate is public and intended to be shared. It’s the 
> private key that’s sensitive. What you’re describing is called “key-pinning”: 
> restricting a client to connect only with a server with a known public key.

That is very reassuring to know. Thanks for the confirmation.

> That was fast! This is frustrating stuff to implement. Or maybe the docs have 
> gotten a lot better recently ;-)

I am great, am I not? (Well, to be honest, I have been struggling with this for 
weeks, and also borrowed heavily from the Apple sample code TLSTool)

> If every instance of the server has its own key, then embedding a cert in the 
> client app doesn’t work.

This project is for my own personal use. So there is just one server.

> The situation you want to watch out for is where the client connects to a 
> server it’s already connected to, but the cert’s public key doesn’t match the 
> previous one. 

In this case the client will close the connection immediately.


Kind regards,

Gerriet.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Jens Alfke

> On Jun 25, 2016, at 7:44 PM, Gerriet M. Denkmann  wrote:
> 
> Following TN2326 I created a (self signed) Certificate Authority and a 
> Digital Identity called "MyServerId".

You probably used the Keychain Access app for this? That works fine, but you’ll 
probably want every instance of the server app to create its own key-pair and 
cert, and you don’t want the user to have to use Keychain Access. I’ve got some 
utility code in my MYUtilities library that will create an Identity (key pair + 
cert) programmatically:
https://github.com/snej/MYUtilities/blob/master/MYAnonymousIdentity.h
The MYGetOrCreateAnonymousIdentity() function returns a SecIdentityRef you can 
use with CFStream.

> Absolutely not sure whether the code above is correct, but it seems to be 
> working.

That was fast! This is frustrating stuff to implement. Or maybe the docs have 
gotten a lot better recently ;-)

> Currently (as indicated in the code above) my client has a copy of the real 
> server certificate and compares it with the certificate obtained from its 
> inputStream.
> I am not sure whether putting the server certificate into the client is ok or 
> a breach of security. 

It’s fine; the certificate is public and intended to be shared. It’s the 
private key that’s sensitive. What you’re describing is called “key-pinning”: 
restricting a client to connect only with a server with a known public key.

If every instance of the server has its own key, then embedding a cert in the 
client app doesn’t work. What’s usually done is to have the app store a copy of 
the cert the first time it connects to the server (with the user’s approval), 
and then require the same cert every subsequent time it connects. (This is 
similar to what SSH does, where the first time you connect to a host it tells 
you the key is unknown and asks if you want to trust it.)

The situation you want to watch out for is where the client connects to a 
server it’s already connected to, but the cert’s public key doesn’t match the 
previous one. This is where you sound the alarm to the user — either someone’s 
trying to spoof the real server, or perhaps the server lost its keys and had to 
create a new cert (maybe its disk crashed and there wasn’t a backup of the 
keychain.)

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-26 Thread Keary Suska

> On Jun 25, 2016, at 8:44 PM, Gerriet M. Denkmann  wrote:
> 
> Following TN2326 I created a (self signed) Certificate Authority and a 
> Digital Identity called "MyServerId".
> 


>> We are now falling into the rabbit hole that is peer-to-peer trust & 
>> identity. How is your server going to identify it so that a client will know 
>> that it’s the server it expects? I don’t know whether you’ve given any 
>> thought to this; the answer affects how you’d implement this part of the app.
> 
> I have thought about this, but I am not at all sure that my thoughts are 
> correct.
> Currently (as indicated in the code above) my client has a copy of the real 
> server certificate and compares it with the certificate obtained from its 
> inputStream.
> I am not sure whether putting the server certificate into the client is ok or 
> a breach of security. 
> 
> That is: the client will accept any server which has signed with the server 
> certificate.

Self-signed certificates can only offer encryption, but cannot offer trust 
because they are not verifiable. You can’t use the server certificate as a key 
since you pass that key out to anyone who wants it (in your app), and anyone 
who gets it can impersonate the server.

I am unclear to me whether you are after a client-server (i.e. all servers are 
under your control) or peer-to-peer (i.e. every client is a server and every 
server is a client)) model? With the former everything you need other than 
client verification is inherent in the SSL/TLS protocol (if you use managed and 
verifiable certificates). With the latter, SSL/TLS will not likely serve you as 
to do it correctly will likely be cost prohibitive (unless you can pass that 
cost to the consumer in some way).

That being said, in a peer-to-peer model I would (OTOH) use a public 
key/private key setup, where public keys are swapped and maintained in a trust 
database once a “trust” connection has been made. Pairing a bluetooth keyboard 
is a simple example of how to establish an initial “trust” connection. The 
benefit here is that by encrypting messages with a user’s public key, only the 
designated user can decrypt it, so you get both internal and external security. 
If a customer asks, “how do I know I am talking to whom I think?” You say, “It 
doesn’t matter, because what they get will not be decipherable unless they are 
who they say they are.” This can be followed up with the fact that all 
electronic communications are intercept-able, so the approach is to make the 
information as undecipherable as possible since there is no way to prevent 
interception.

HTH,

Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Security with Streams

2016-06-25 Thread Gerriet M. Denkmann

> On 26 Jun 2016, at 05:12, Jens Alfke  wrote:
> 
> 
>> On Jun 18, 2016, at 2:34 AM, Gerriet M. Denkmann  
>> wrote:
>> 
>> 1. (important) the client really wants to know that:
>>  (1a) it is talking to the right server and not to some evil entity 
>> masquerading as the real server.
>>  (1b) the data it receives has not been tampered with on the way.
> 
> You want an SSL (aka TLS) connection, with the server providing a certificate 
> (the typical setup.)
> 
>> 2. (less important) the server might want to know that the client connecting 
>> to it is a valid client.
>>  This might help if there are thousands of fake clients overwhelming the 
>> server with fake requests.
>>  But this is a kind of unlikely scenario.
> 
> For that you’d need the SSL client to provide a certificate too. This is 
> supported by the CFStream APIs.
> 
>> 3. (hardly important at all) no one can read the data exchanged.
>>  The data exchanged it really not sensitive.
> 
> Well, you get that for free with SSL anyway :)
> 
> Accomplishing (1b) and (3) is straightforward, I think. The doc-comment for 
> NSNetService says how to enable SSL/TLS for the sockets by setting the stream 
> properties:


Following TN2326 I created a (self signed) Certificate Authority and a Digital 
Identity called "MyServerId".

The server gets MyServerId from my keychain:
 
- (void)netService:(NSNetService *)sender 
didAcceptConnectionWithInputStream:(NSInputStream *)inputStream 
outputStream:(NSOutputStream *)outputStream
{
NSString *certificateName = @"MyServerId";
NSDictionary *d =   @{  (__bridge id) kSecClass:
(__bridge id) kSecClassIdentity,
(__bridge id) 
kSecReturnRef:@YES, 
(__bridge id) 
kSecMatchSubjectWholeString:  certificateName,
 };  
CFArrayRef copyMatchingResult;
OSStatus status = SecItemCopyMatching( (__bridge CFDictionaryRef)di, 
(CFTypeRef *)©MatchingResult );
if (status != errSecSuccess)...

id mySecIdentityRef = (__bridge id)copyMatchingResult;
NSArray *certs = @[ mySecIdentityRef ];
NSDictionary *settings =@{  (__bridge NSString 
*)kCFStreamSSLValidatesCertificateChain: @NO,

(__bridge NSString *)kCFStreamSSLIsServer:  
@YES,

(__bridge NSString *)kCFStreamSSLCertificates:  certs,
 };
BOOL ok = [ inputStream setProperty: settings  forKey: (__bridge 
NSString *)kCFStreamPropertySSLSettings ];
if ( !ok )  ...

... for both streams: scheduleInRunLoop, open
}


The client has a copy of MyServerId.cer (exported from my keychain) in its 
bundle.

- (void)netService:(NSNetService *)sender 
didAcceptConnectionWithInputStream:(NSInputStream *)inputStream 
outputStream:(NSOutputStream *)outputStream
{
NSDictionary *settings = @{ (__bridge NSString 
*)kCFStreamSSLValidatesCertificateChain: @NO };
BOOL ok = [ inputStream setProperty: settings  forKey: (__bridge 
NSString *)kCFStreamPropertySSLSettings ];
if ( !ok )  ...

... for both streams: scheduleInRunLoop, open
}

The NSStreamDelegate of the client compares the certificate in inputStream with 
the certificate in its bundle:

- (void)stream:(NSStream *)aStream  handleEvent: (NSStreamEvent)streamEvent 
{
if ( streamEvent & NSStreamEventHasSpaceAvailable ) 
{
if ( firstTimeHere )
{
firstTimeHere = NO;

NSString *kSSLPeerTrust = (__bridge NSString 
*)kCFStreamPropertySSLPeerTrust;
id trusT = [ inputStream propertyForKey: kSSLPeerTrust 
];   
if ( trusT == nil ) … error badServer

SecTrustRef trust = (__bridge SecTrustRef)trusT;
SecTrustResultType  trustResult;//  will 
be: recoverable trust failure; probably because certificate is based on self 
signed Certificate Authority 
OSStatus err = SecTrustEvaluate(trust, &trustResult);
if (err != errSecSuccess)   … error badServer

if trustResult ≠ kSecTrustResultProceed, 
kSecTrustResultUnspecified, kSecTrustResultRecoverableTrustFailure ... 
error badServer

SecCertificateRef certificate = 
SecTrustGetCertificateAtIndex ( trust, 0 );
if ( certificate == nil )   ... error badServer


Re: Security with Streams

2016-06-25 Thread Jens Alfke

> On Jun 18, 2016, at 2:34 AM, Gerriet M. Denkmann  wrote:
> 
> 1. (important) the client really wants to know that:
>   (1a) it is talking to the right server and not to some evil entity 
> masquerading as the real server.
>   (1b) the data it receives has not been tampered with on the way.

You want an SSL (aka TLS) connection, with the server providing a certificate 
(the typical setup.)

> 2. (less important) the server might want to know that the client connecting 
> to it is a valid client.
>   This might help if there are thousands of fake clients overwhelming the 
> server with fake requests.
>   But this is a kind of unlikely scenario.

For that you’d need the SSL client to provide a certificate too. This is 
supported by the CFStream APIs.

> 3. (hardly important at all) no one can read the data exchanged.
>   The data exchanged it really not sensitive.

Well, you get that for free with SSL anyway :)

Accomplishing (1b) and (3) is straightforward, I think. The doc-comment for 
NSNetService says how to enable SSL/TLS for the sockets by setting the stream 
properties:

 * To enable TLS on the stream, set the various TLS settings using
 * kCFStreamPropertySSLSettings before calling -open. You must also specify
 * kCFBooleanTrue for kCFStreamSSLIsServer in the settings dictionary along with
 * a valid SecIdentityRef as the first entry of kCFStreamSSLCertificates.
 */
- (void)netService:(NSNetService *)sender 
didAcceptConnectionWithInputStream:(NSInputStream *)inputStream 
outputStream:(NSOutputStream *)outputStream NS_AVAILABLE(10_9, 7_0);

It doesn’t say so, but I’m guessing you need to set the 
kCFStreamPropertySSLSettings property on the client side too (but not IsServer 
or Certificates), otherwise the client will try to open a plain socket and the 
SSL handshake will fail.

The harder part is (1a) because it gets into the issues of “trust” and 
“identity”, which are quite deep and complex. Your server app will need to 
provide an X.509 certificate when it accepts a connection. The usual way to get 
these is from a certificate authority like Verisign or Comodo (or now, Let’s 
Encrypt), but they issue certificates for DNS domain names, and your server 
probably doesn’t run on a host with its own domain name, since you’re just 
connecting to it via a raw IP address. The other option is getting a cert for 
an email address, but those are marked as being for use only in signing mail 
messages, not for SSL.

We are now falling into the rabbit hole that is peer-to-peer trust & identity. 
How is your server going to identify it so that a client will know that it’s 
the server it expects? I don’t know whether you’ve given any thought to this; 
the answer affects how you’d implement this part of the app.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Security with Streams

2016-06-17 Thread Gerriet M. Denkmann
I have a server macOS app which publishes a service via NSNetService.
And a client iOS app which finds this service via NSNetServiceBrowser.

Then the client sends commands to the server via NSOutputStream and receives 
data from the server via NSInputStream.

All this works fine - but there is currently no security at all.

I would like to achieve these goals:

1. (important) the client really wants to know that:
(1a) it is talking to the right server and not to some evil entity 
masquerading as the real server.
(1b) the data it receives has not been tampered with on the way.

2. (less important) the server might want to know that the client connecting to 
it is a valid client.
This might help if there are thousands of fake clients overwhelming the 
server with fake requests.
But this is a kind of unlikely scenario.

3. (hardly important at all) no one can read the data exchanged.
The data exchanged it really not sensitive.

I have no experience with security.
Can anybody point me in the right direction?

Gerriet.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com