2013年6月30日日曜日

WindowsストアアプリでTLS/SSL自己署名証明書を使う

Socket、HTTP、WebSocket通信はTLS/SSLを使って暗号化されることが多いが、Windowsストアプリでは証明書拡張機能を使ってアプリケーションと一緒にTLS/SSL証明書をインストールする方法が用意されている。
以下、WindowsストアアプリにおいてTLS/SSL自己証明書をインストールする方法について説明する。


1. 証明書を準備する


Windowsストアアプリでは通信接続先のサーバホスト名と証明書のCommon Nameが一致しているかチェックされるため、 前回の内容を参考に、Common NameについてFQDNまたはIPアドレスを正確に指定して自己署名証明書を作成する。
今回はserver-crt-192p168p1p101.pem(サーバIPアドレスが192.168.1.101)とserver-crt-192p168p1p102.pem(サーバIPアドレスが192.168.1.102)の2つのファイルを作成済みと仮定して進めていく。


2. アプリに証明書を配置する


準備した証明書ファイルをドラッグ&ドロップによりWindowsストアプリの適当な場所に配置する(下記例ではAssetディレクトリ以下に証明書ファイルを配置)。
各証明書ファイルのプロパティについて下記の通り設定する。
  • ビルドアクション: コンテンツ
  • 出力ディレクトリにコピー: 常にコピーする


3. マニフェスト宣言を行う

  1. サポートされる宣言について証明書を選択する。
  2. 各証明書について、ストア名にはRoot、コンテンツには該当証明書ファイル場所を入力する。
  3. 複数の証明書をアプリ側(アプリコンテナ)から自動選択させる場合は、自動選択にチェックを入れる。

Package.appxmanifestファイルに直接XML形式で記述する際は、Extensionsタグ内に記述する。
  </Capabilities>
  <Extensions>
  <!-- Certificates Extension START -->
    <Extension Category="windows.certificates">
      <Certificates>
        <Certificate StoreName="Root" Content="Assets\server-crt-192p168p1p101.pem" />
        <Certificate StoreName="Root" Content="Assets\server-crt-192p168p1p102.pem" />
        <SelectionCriteria AutoSelect="true" />
      </Certificates>
    </Extension>
  <!-- Certificates Extension END -->
  </Extensions>
</Package>

[参考URL]
How to connect to a Http Rest Service with Self Signed Certificate(in the server side).

2013年6月25日火曜日

TLS/SSL自己署名証明書を作成する

opensslコマンドを使ってTLS/SSLテスト用証明書を用意する。
非商用の場合はCAcert.org等から証明書を取得する方法もあるが、今回は内部テストでのみ利用するため、自己署名証明書(いわゆるオレオレ証明書)を作成することにする。


1. 秘密鍵を作成する。


作成する秘密鍵ファイル名をserver-key-192p168p1p101.pemとする。
$ openssl genrsa -out server-key-192p168p1p101.pem 2048


2. 証明書署名要求を作成する。


作成する証明書署名要求ファイル名をserver-csr-192p168p1p101.pemとする。
$ openssl req -new -key server-key-192p168p1p101.pem -out server-csr-192p168p1p101.pem

各種設定例は下記の通り。
Common Nameについては実際にTLS/SSLを使用するサーバのFQDNまたはIPアドレスを指定する事。
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Shinagawa-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Hoge Limited
Organizational Unit Name (eg, section) []:Piyo Unit
Common Name (e.g. server FQDN or YOUR name) []:192.168.1.101
Email Address []:foo@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:


3. 自己署名証明書を作成する。


作成する自己署名証明書ファイル名をserver-crt-192p168p1p101.pemとする。
$ openssl x509 -req -days 365 -in server-csr-192p168p1p101.pem -signkey server-key-192p168p1p101.pem -out server-crt-192p168p1p101.pem


[参考URL]SSL証明書インストールに関するメモ

2013年6月23日日曜日

iOSでHTTPリクエストする

比較的単純なHTTPリクエストを実行する際は、非同期リクエストであるNSURLConnectionクラスのsendAsynchronousRequest:queue:completionHandler:クラスメソッドを利用する。
本APIはiOS5.0から利用可能。

第3引数completionHandlerにはデータ取得時に実行するBlock文を記述する。このBlock文は第2引数queueで指定したNSOperationQueue上で実行される。以下のコード例ではBlock文はメインスレッドで実行されることになる。

環境
  • Xcode 4.6.3
  • ARC ON
  • iPhone 6.1 Simulator
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *requestUrl;
@property (weak, nonatomic) IBOutlet UITextField *requestBody;
@property (weak, nonatomic) IBOutlet UITextView *requestResult;
- (IBAction)getAsync:(id)sender;
- (IBAction)postAsync:(id)sender;

@end
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// HTTP-GET
- (IBAction)getAsync:(id)sender {
    NSLog(@"%@#%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    // Create the url-request.
    NSURL *url = [NSURL URLWithString:self.requestUrl.text];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    // Set the method(HTTP-GET)
    [request setHTTPMethod:@"GET"];

    // Send the url-request.
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {   
        if (data) {
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"result: %@", result);
            self.requestResult.text = result;
        } else {
            NSLog(@"error: %@", error);
            self.requestResult.text = [NSString stringWithFormat:@"error: %@", error];
        }
    }];
    
}

// HTTP-POST
- (IBAction)postAsync:(id)sender {
    NSLog(@"%@#%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    // Create the url-request.
    NSURL *url = [NSURL URLWithString:self.requestUrl.text];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    // Set the header(s).
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    // Set the method(HTTP-POST)
    [request setHTTPMethod:@"POST"];

    // Set the request-body.
    NSString *reqBody = self.requestBody.text;
    NSLog(@"reqBody: %@", reqBody);
    [request setHTTPBody:[reqBody dataUsingEncoding:NSUTF8StringEncoding]];

    // Send the url-request.   
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        
        if (data) {
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"result: %@", result);
            self.requestResult.text = result;
        } else {
            NSLog(@"error: %@", error);
            self.requestResult.text = [NSString stringWithFormat:@"error: %@", error];
        }
    }];
  
}

@end