Wings of Hermes – Berin's Infosec Blog

Infosec the world and everything

I was doing some reading on the distribute.it hack and stumbled onto a reference to a Risky Business podcast on probablistic risk assessments.

It’s a great argument as to why risk assessment does not work well in the information security space.  The basic thesis is you can’t assign a probability to a serious attacker.    We’ve built a whole risk model on the idea that we can assign a probability to various events – we treat risk in a malicous environment as we would in a "normal" environment.  We have a certain risk of machine failure therefore we have a similarly measurable risk on a malicious attacker and of course these two are not equivalent at all.

A great interview to listen to.

I read No pic, no fly plan for airports in The Age yesterday with a small amount of dismay.  It’s always frustrating to see security measures that seem to be more about the appearance of security rather than the reality, and which will negatively impact the users (or travellers in this case).

I’m really not sure how having to produce a photo ID will really slow down the determined criminal or terrorist. I’m pretty sure it’s not going to give them pause for thought.

And as for signing a stat-dec if you don’t have ID – what does that achieve?

I do like the idea of getting a newborn to sign a stat dec tho….

Very belatedly I’ve been looking into the Stuxnet worm. Interesting new world we find ourselves in. This thing was surgical – not only damaging the equipment but hiding its footsteps.

The question you have to ask though is if this is the one we know about – how many are out there that we don’t?


So following from my post on exporting a public key from an iPhone into java, here is some sample code for going the other way.

It follows the same logic as exporting the key but in reverse. (It starts with decoding the Base64 piece as the app I am working on always passes data in encoded format.)

Once it’s base 64 decoded it strips the ASN.1 encoding associated with the OID and sequence encoding that generally prepends the RSA key data. That leaves it with just the large numbers that make up the public key.

The key loading parts are heavily based on the Crypto example provided by Apple. It’s not been extensively tested, but it works with the few keys I’ve thrown at it. (refString is just a string constant I define elsewhere that identifies the key in the key store.)

Let me know what you find that’s wrong! I’d also be interested in knowing how to do this without saving the key as a persistent reference. I didn’t have time to work out how to do that part (assuming it’s possible).

- (BOOL) setPublicKey: (NSString *) keyAsBase64 {

    /* First decode the Base64 string */
    Base64 * b64 = [[Base64 alloc] init];
    NSData * rawFormattedKey = [b64 base64decode:[keyAsBase64 UTF8String] length:[keyAsBase64 length]];
    
    /* Now strip the uncessary ASN encoding guff at the start */
    unsigned char * bytes = (unsigned char *)[rawFormattedKey bytes];
    size_t bytesLen = [rawFormattedKey length];
    
    /* Strip the initial stuff */
    size_t i = 0;
    if (bytes[i++] != 0x30)
        return FALSE;
    
    /* Skip size bytes */
    if (bytes[i] > 0x80)
        i += bytes[i] - 0x80 + 1;
    else 
        i++;
    
    if (i >= bytesLen)
        return FALSE;
    
    if (bytes[i] != 0x30)
        return FALSE;

    /* Skip OID */
    i += 15;
    
    if (i >= bytesLen - 2)
        return FALSE;

    if (bytes[i++] != 0x03)
        return FALSE;
    
    /* Skip length and null */
    if (bytes[i] > 0x80)
        i += bytes[i] - 0x80 + 1;
    else 
        i++;

    if (i >= bytesLen)
        return FALSE;

    if (bytes[i++] != 0x00)
        return FALSE;

    if (i >= bytesLen)
        return FALSE;
    
    /* Here we go! */
    NSData * extractedKey = [NSData dataWithBytes:&bytes[i] length:bytesLen - i];

    /* Load as a key ref */
    OSStatus error = noErr;
    CFTypeRef persistPeer = NULL;
    
    NSData * refTag = [[NSData alloc] initWithBytes:refString length:strlen(refString)];
    NSMutableDictionary * keyAttr = [[NSMutableDictionary alloc] init];
    
    [keyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [keyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [keyAttr setObject:refTag forKey:(id)kSecAttrApplicationTag]; 
    
    /* First we delete any current keys */
    error = SecItemDelete((CFDictionaryRef) keyAttr);
    
    [keyAttr setObject:extractedKey forKey:(id)kSecValueData];
    [keyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];
    
    error = SecItemAdd((CFDictionaryRef) keyAttr, (CFTypeRef *)&persistPeer);
    
    if (persistPeer == nil || ( error != noErr && error != errSecDuplicateItem)) {
        NSLog(@"Problem adding public key to keychain");
        return FALSE;
    }
    
    CFRelease(persistPeer);
    
    publicKeyRef = nil;
    
    /* Now we extract the real ref */
    [keyAttr removeAllObjects];
    /*
    [keyAttr setObject:(id)persistPeer forKey:(id)kSecValuePersistentRef];
    [keyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
    */
    [keyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [keyAttr setObject:refTag forKey:(id)kSecAttrApplicationTag];
    [keyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [keyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
    
    // Get the persistent key reference.
    error = SecItemCopyMatching((CFDictionaryRef)keyAttr, (CFTypeRef *)&publicKeyRef);    

    if (publicKeyRef == nil || ( error != noErr && error != errSecDuplicateItem)) {
        NSLog(@"Error retrieving public key reference from chain");
        return FALSE;
    }
    

    return TRUE;
}


I was forwarded an article today from the BBC news website – Zurich Insurance fined £2.3m over customers’ data loss .  It’s a fairly standard article about a financial institution being fined for  losing customer data.

What really struck me though was a comment in the article from the FSA – “Firms across the financial sector would do well to look at the details of this case and learn from the mistakes that Zurich UK made…“.  That’s true.  But what concerns me is the real focus on fincos with this stuff.  There are so many other companies now holding our private data – and in many cases they are holding more than the financial institutions do.

Shouldn’t we be maturing this argument now to extend beyond financial institutions?  There should a duty of care for any company holding my data.  Financials can lead the way – but we need to hold other companies accountable as well.

Network World have an interesting article based on a Forrester research report on iPhone and iPad security, arguing it’s good enough for most cases.

I seem to be struggling with lots of things lately that should be easy, but I just can’t find an easy way to do them. My latest struggle has been using NSURLConnection to connect to an SSL site that is secured using my root certificate. There is no easy reference anywhere for how to do this without loading the root cert into the user’s general key store – which is fiddly and not the best in some circumstances.

In my case I use cacert.org as my root cert and I don’t want to force the end user to trust all sites signed by cacert.org, I just want my SSL connection to work inside my app.

So it turns out there are two methods that you need to use in the NSURLConnection delegate class. Both are referenced in many places, but it’s generally to tell you how to completely bypass any check. You can also use them to check against your own root cert.

First of all, you implement -(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace so that for server authentication requests the NSURLConnection class knows you can handle them.

Then you implement – (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge to actually handle the check. The code is pretty simple.

As a note – rootCert in the attached code is a reference to a certificate I loaded from a file (DER encoded).

#pragma mark -
#pragma mark Connection Authentication Handling

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    
    #pragma unused(conn)

    NSString * challenge = [protectionSpace authenticationMethod];
    if ([challenge compare:NSURLAuthenticationMethodServerTrust] == 0) {
        return YES;
    }
    
    return NO;
    
}

/* Look to see if we can handle the challenge */

- (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    #pragma unused(conn)
    
    NSLog(@"didReceiveAuthenticationChallenge %@ %zd", [[challenge protectionSpace] authenticationMethod], (ssize_t) [challenge previousFailureCount]);
    
    NSURLCredential *   credential = nil;
    NSURLProtectionSpace *  protectionSpace;
    SecTrustRef             trust;
    int                        err;

    /* Setup */        
    protectionSpace = [challenge protectionSpace];
    trust = [protectionSpace serverTrust];
    credential = [NSURLCredential credentialForTrust:trust];

    /* Set up the array of certs we will authenticate against and create cred */
    NSArray * certs = [[NSArray alloc] initWithObjects:(id)rootCert,nil];
    credential = [NSURLCredential credentialForTrust:trust];
        
    /* Build up the trust anchor using our root cert */    
    
    err = SecTrustSetAnchorCertificates(trust, (CFArrayRef) certs);
    SecTrustResultType trustResult = 0;
    if (err == noErr) {
        err = SecTrustEvaluate(trust, &trustResult);
    }
    
    [certs release];
    
    BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));

    // Return based on whether we decided to trust or not

    if (trusted)
        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    else {
        NSLog(@"Trust evaluation failed for service root certificate");
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }

}

Again – I reckon there will be a quicker way to do this and probably some bugs in what I’ve done – feel free to comment and set me on the straight and narrow!


Strange.

com.sun.org.apache.xml.internal.security.utils.Base64 is a part of the base Java 1.6 runtime (it’s found in rt.jar). But Netbeans throws errors on it unless you include the METRO 2.0 jar file as a library to compile against (you don’t need to package it).

Or at least that’s the case on Windows. On OS X it just works.

What a waste of an evening

I’ve spent the last two days working through this – and couldn’t find any easy code at all on the net. So to save others the time here is what I found.

First off, when you export a key from the iPhone keychain, it’s exported in a cut down format – just the public key and exponent without any of the other ASN.1 stuff you’d expect in a fully encoded public key. The java crypto functions generally expect a fully encoded key (OID and all). So I quickly whipped up some Objective C code to take the exported key and expand it out to a fully interoperable key in the X.509 format.

I’m darn sure there is an easier way to do this, I just couldn’t for the life of me find it. Please let me know what I’ve missed or any bugs/errors/plain sillies in the attached following code

First off a simple function to encode ASN.1 length fields:

// Helper function for ASN.1 encoding

size_t encodeLength(unsigned char * buf, size_t length) {

    // encode length in ASN.1 DER format
    if (length < 128) {
        buf[0] = length;
        return 1;
    }

    size_t i = (length / 256) + 1;
    buf[0] = i + 0x80;
    for (size_t j = 0 ; j < i; ++j) {         buf[i - j] = length & 0xFF;         length = length >> 8;
    }

    return i + 1;
}

OK – with that in place, some code to actually do the encoding. The following is a full copy of a function from something I’m working on. The Base64 class is a very simple encoding/decoding class I built.


#define _MY_PUBLIC_KEY_TAG "my_key_identifier"

- (NSString *) getRSAPublicKeyAsBase64 {

    static const unsigned char _encodedRSAEncryptionOID[15] = {

        /* Sequence of length 0xd made up of OID followed by NULL */
        0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
        0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00

    };
    
    NSData * publicTag =
        [NSData dataWithBytes:_MY_PUBLIC_KEY_TAG
                       length:strlen((const char *) _MY_PUBLIC_KEY_TAG)];

    // Now lets extract the public key - build query to get bits
    NSMutableDictionary * queryPublicKey =
        [[NSMutableDictionary alloc] init];

    [queryPublicKey setObject:(id)kSecClassKey
                       forKey:(id)kSecClass];
    [queryPublicKey setObject:publicTag
                       forKey:(id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(id)kSecAttrKeyTypeRSA
                       forKey:(id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES]
                       forKey:(id)kSecReturnData];

    NSData * publicKeyBits;
    OSStatus err =
        SecItemCopyMatching((CFDictionaryRef)queryPublicKey,
                            (CFTypeRef *)&publicKeyBits);

    if (err != noErr) {
        return nil;
    }

    // OK - that gives us the "BITSTRING component of a full DER
    // encoded RSA public key - we now need to build the rest

    unsigned char builder[15];
    NSMutableData * encKey = [[NSMutableData alloc] init];
    int bitstringEncLength;

    // When we get to the bitstring - how will we encode it?
    if  ([publicKeyBits length ] + 1  < 128 )
        bitstringEncLength = 1 ;
    else
        bitstringEncLength = (([publicKeyBits length ] +1 ) / 256 ) + 2 ; 

    // Overall we have a sequence of a certain length
    builder[0] = 0x30;    // ASN.1 encoding representing a SEQUENCE
    // Build up overall size made up of -
    // size of OID + size of bitstring encoding + size of actual key
    size_t i = sizeof(_encodedRSAEncryptionOID) + 2 + bitstringEncLength +
               [publicKeyBits length];
    size_t j = encodeLength(&builder[1], i);
    [encKey appendBytes:builder length:j +1];

    // First part of the sequence is the OID
    [encKey appendBytes:_encodedRSAEncryptionOID
                 length:sizeof(_encodedRSAEncryptionOID)];

    // Now add the bitstring
    builder[0] = 0x03;
    j = encodeLength(&builder[1], [publicKeyBits length] + 1);
    builder[j+1] = 0x00;
    [encKey appendBytes:builder length:j + 2];

    // Now the actual key
    [encKey appendData:publicKeyBits];

    // Now translate the result to a Base64 string
    Base64 * base64 = [[Base64 alloc] init];
    NSString * ret = [base64 base64encode:[encKey bytes]
                                   length:[encKey length]];
    [base64 release];
    [encKey release];
    return ret;
}

As I said – I’m very sure there is an easier way to do this. If someone can tell me what it is I’d be most grateful!

And if you need some code to import into a Java key – the following is a cut from the java app I am building. Clearly you will want to get a bit prettier on the exception handling :).

        byte[] decodedPublicKey;
        try {
            // Now lets encrypt the nonce
            decodedPublicKey = Base64.decode(d.getPublicKey());
        } catch (Base64DecodingException ex) {
            logger.log(Level.WARNING,
               "getDeviceInfo - error decoding public key for device:{0}",
               deviceId);
            return di;
        }
        PublicKey publicKey;
        try {
            publicKey = KeyFactory.getInstance("RSA").
                generatePublic(new X509EncodedKeySpec(decodedPublicKey));
        } catch (Exception ex) {
            logger.log(Level.WARNING,
               "getDeviceInfo - error importing public key for device:{0}",
                deviceId);
            return di;
        }

 

Read an interesting article Gartner: Companies shouldn’t bother banning Facebook, social networking
this morning around Gartner’s security guy Andrew Walls and his view on the value of blocking social media.

I tend to agree with his argument that security people risk loosing credibility if they keep saying these sites are dangerous when people use them freely at home and don’t seem to get badly hurt. A real case of the history not supporting the risk statement. And people do keep saying it’s a massive malware risk – letting people browse the Internet is a Malware risk full stop. We haven’t stopped that yet!

I also like his thinking about the relative value to the organization of people with large social networks. They are probably the people who will provide the most value. I think the value it brings is a key input to the risk reward equation that companies use when making these decisions.

But the bit that really struck me was that last year the percentage of Gartner client companies blocking social media was 75%. This year it is at 60%. That’s a big jump in a short time. The absolute percentages won’t represent the broader community – I’m not sure that many companies really filter the Internet. But the relative values still say a lot.

Maybe us security peeps need to “just get over it”.