Re: Security with Streams
> 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
> 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
> 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
> 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
> 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
> 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
> 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
> 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
> 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
> 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
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