Quantcast
Channel: Certified Security Solutions » Public Key Infrastructure
Viewing all articles
Browse latest Browse all 27

In-App Mobile Certificates Made Easy with mCMS (Part 1)

$
0
0

The ability to install certificates on iOS devices has been well-supported since iOS 4.2. The Mobile Certificate Management System (mCMS) currently provides a secure mechanism for installing certificates onto iOS devices using your Microsoft-based PKI.  These certificates can be used for apps/services built into iOS directly – VPN, Wireless, etc.  3rd-party apps installed on the iOS devices, however, cannot use these certificates and private keys because of the iOS security model.   3rd-party apps are forced to obtain, store, and use their own certificates, without any support from the underlying OS.

Obtaining, storing, and using certificates securely is not trivial.  Microsoft currently offers two interfaces for obtaining certificates from a CA.  The first is a Win32/COM mechanism that can be used from C++/.NET clients.  The other interface is the Certificate Enrollment Web Services, which is a SOAP-based mechanism built with the WS-Security standards.  While these approaches work well for Windows Desktop and Server applications, neither approach is suitable for mobile devices which lack the horsepower and software frameworks to use SOAP or COM.

mCMS bridges the gap between mobile apps and your Microsoft PKI, making it simple and secure to utilize in-app certificates for your mobile applications.  Additionally, the upcoming release of mCMS includes several types of APIs that you can use directly.  Certificate enrollment support begins with a REST-based API that is accessible by standard HTTP protocol over SSL.  This API is universally available to any technology platform that supports REST-based APIs.  It uses JSON to exchange information with the mCMS Server.  CSS will also provide a higher-level, platform-specific API library to make certificate enrollment even easier than our REST-based API.  Initially, these platform-specific libraries will be available for iOS (Objective-C) and Android (Java).  Future support for Windows Phone 7.5/8 is planned as well.

                       

Figure 1:  API Components

 App developers are free to use either the REST-based API or the included platform-specific API as appropriate.  The remainder of this blog post will focus on building an iOS app using the Objective-C API library which will be included in our SDK.

Obtain a certificate with mCMS in 4 easy steps

  1. Create an instance of the MCMSCertEnrollAPI class, initialized with property values
  2. Read the Status of the MCMS Server
  3. Read the available Certificate Templates
  4. Request a certificate based on an available template

Let’s break these steps down a bit further.

Step 1

The MCMSCertEnrollAPI provides a compact Objective-C interface for software applications to work with.  By initializing it with properties, the class will handle most of the details for obtaining certificates.  Most likely, all but the userName and password field values will be compiled into your application.  The app should provide a UI for you to enter your Windows AD credentials to make them available to the app.

Here’s an example of how an instance is created:

self.certEnrollApi = [[MCMSCertEnrollApi alloc] initWithProperties:APP_KEY
                                                     withAppSecret:APP_SECRET
                                                     withServerUrl:serverUrl
                                                      withUserName:userName
                                                      withPassword:password
                                                 withVirtualFolder:@"mCMSWebApi"];

Step 2

Read the status of the mCMS Server.  This is an optional, but recommended, step to make sure that the version of the mCMS Server matches the version that the app is expecting.

[self.certEnrollApi readServerStatus:^(ApiVersion *apiVersion) {
    //Log the details received from the server.
    NSLog(@"Api Version: Major=%@, Minor=%@, ProdMajorRev=%@, ProdMinorRev=%@",
        apiVersion.apiMajorRev, apiVersion.apiMinorRev, apiVersion.productMajorRev, apiVersion.productMinorRev);
} failure:^(NSError *error) {  //Handle failure in this block
    NSString *errorString =
        [[NSString alloc] initWithFormat:@"HTTP Code = %@, Error Code = %@, Error Message = %@",
            [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_HTTP_STATUS_CODE],
            [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_EXTENDED_STATUS_CODE],
            [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_SERVER_MESSAGE]];
    NSLog(@”Error received from the mCMS Server: %@”, errorString);
}];

The first block handles the success response from the mCMS server and logs some of the ApiVersion property values to the trace system.  At this point, your software application is ready to read templates and/or request a certificate.  The second block handles the failure response from the server.  The mCMS Cert Enroll library will return a rich NSError object containing the relevant error details.  The userInfo method will return an NSDictionary object containing the 3 keys that contain the error details.  This rich error information should give your app enough information to know exactly why it failed to read the server status.

Step 3

Read the certificate templates that the mCMS Server has been configured to offer to your app.  The certificate template will contain several pieces of information, including the size of the key that the certificate template specifies.

[self.certEnrollApi readAvailableTemplates:^(NSArray *templates) {
    certificateTemplates = [[NSArray alloc] initWithArray:templates];
    [self performSelectorOnMainThread:@selector(updateDefaultTemplate:) withObject:nil waitUntilDone:NO];
} failure:^(NSError *error) {
    NSString *errorString = [[NSString alloc] initWithFormat:@"HTTP Code = %@, Error Code = %@, Error Message = %@",
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_HTTP_STATUS_CODE],
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_EXTENDED_STATUS_CODE],
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_SERVER_MESSAGE]];
    NSLog(@”Error received from the mCMS Server: %@”, errorString);
}];

In the success block, the array of Template objects received from the server is passed.  In the code above, a local copy of the data is made, and a selector is executed on the UI thread to update the UI with the selected template.  It’s likely that this level of detail would not be exposed to the user, so this method can be used to verify that the expected template is available.  As in the previous step, the failure block logs the server error.

Step 4

Enroll for the certificate.  Only two parameters are required for this final step.  The app must supply the name of the certificate template to enroll with, and an identityName value which is used to import the resulting certificate into the app’s keychain.

[self.certEnrollApi enrollForCertificateWithPkcs10:[certTemplateName text]
                                      identityName:self.userName
                                           success:^(CFDataRef identityRef, NSString *identityName) {
    KeychainExamples *key = [[KeychainExamples alloc] init];
    SecIdentityRef secIdentityRef = [key identityForPersistentRef:identityRef];
    if(secIdentityRef != nil)
    {
        /////////////////////////////////////////////////////////////////////////
        //
        //  Successfully getting a SecIdentityRef object at this point allows us
        //  to do any number of operations.  We can check for Certificate Trust,
        //  use the cert for encryption/decryption, etc.
        SecCertificateRef certificateRef = [key certificateFromIdentity];
        if(certificateRef != nil)
        {
            NSString *certSubject = [key getCertificateSubject];
            NSString *certIssuer = [key getCertificateIssuer];
            NSDate *certExp = [key getCertificateExpiration];
            NSString *certMessage =
                [[NSString alloc] initWithFormat:@"Certificate Subject: <a>%@\nCertificate> Issuer: %@\nExpiration: %@", certSubject, certIssuer, [certExp description]];

            //Display an Alert message with the certificate details.
            [self performSelectorOnMainThread:@selector(displayCertificateAlert:) withObject:certMessage waitUntilDone:NO];
       }
 }
} failure:^(NSError *error) {
    NSString *errorString = [[NSString alloc] initWithFormat:@"HTTP Code = %@, Error Code = %@, Error Message = %@",
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_HTTP_STATUS_CODE],
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_EXTENDED_STATUS_CODE],
        [[error userInfo] valueForKeyPath:MCMS_ERROR_KEY_SERVER_MESSAGE]];
    NSLog(@”Error received from the mCMS Server: %@”, errorString);
}];

Several things happen on the iOS device when the enrollForCertificateWithPkcs10 method is called.

  1. A Public/Private keypair is generated on the device based on the Certificate Template properties.
  2. A PKCS#10 is generated on the device.
  3. The PKCS#10 is sent as an enrollment request to the mCMS Server
  4. The mCMS Server enrolls with the Microsoft CA to request a certificate for the user
  5. The new certificate is returned from the mCMS Server and ultimately to the iOS app

In the success block, a CFDataRef object is passed to the block.  This is a persistable object that can be used to retrieve the associated SecIdentityRef which is stored in the app’s keychain.  The app can persist this object, so that in future executions it can once again gain access to the key/certificate.  In OSX/iOS, the SecIdentityRef object contains both a certificate and the corresponding private key (essentially a P12 type of container).  With our included KeychainExamples class, it is simple to retrieve the SecCertificateRef (the certificate) and SecKeyRef (the private key) objects from the SecIdentityRef object.

One downside of the iOS Keychain API is that its support for certificates is limited.  To examine the content of the certificates, I had to load the certificate bytes into OpenSSL’s certificate structures.  Once it was in that format, it was easy to look at the expiration date, subject, issuer, etc.  Some examples of this are in the KeychainExamples class that ships with our SDK.

Keep reading: Part II, Certificate Enrollment for the Android Platform.


Viewing all articles
Browse latest Browse all 27

Trending Articles