Win32APIを使ってWindowsでSSLを実装する

SSPIやらSchannelでMSDNを検索するとわらわら出てくるけどメモってことで。

Client側の手順

  • Hello送信
    1. InitializeSecurityContextでトークンを作成
    2. sendでトークンを送信
  • ハンドシェイク
    1. recvでトークンを受信
    2. InitializeSecurityTokenに受信したトークンを渡してトークンを生成
    3. sendでトークンを送信
    4. 上記1〜3の処理をSEC_E_OKが返るまで続ける
    5. 途中でSEC_I_INCOMPLETE_CREDENTIALSが返ってきたらクライアント認証用の証明書をセットしてハンドシェイクを続行
  • データの送信
    1. EncryptMessageでデータブロックを暗号化
    2. sendで送信
  • データの受信
    1. recvで受信
    2. DecryptMessageで復号
    3. DecryptMessageに渡したバッファの中からSECBUFFER_DATAタイプのものを探す
    4. そこに復号済みデータがあるので受信データ受け取り用バッファにコピーする
    5. DecryptMessageに渡したバッファの中のSECBUFFER_EXTRAタイプのものには未復号のデータが入っているので、復号後のデータ量が足りない場合や次回受信時に復号する
    6. DecryptMessageでSEC_E_INCOMPLETE_MESSAGEが返る場合は再度recv
    7. SEC_I_RENEGOTIATEが返ってきたときはハンドシェイクをやり直す
  • 通信終了
    1. ApplyControlTokenを呼び出して自分にShutdownを通知
    2. InitializeSecurityContextでシャットダウントークンを生成
    3. sendで送信

Server側の手順
InitializeSecurityContextの代わりにAcceptSecurityContextを呼び出すだけで後はほとんど同じ。
ただしサーバー認証用の証明書をセットしたりしなきゃならないのでちと面倒。
サーバー証明書についてはPCredHandleをInitializeSecurityContextに渡せばよいだけなのでPCredHandleを作る方法をメモしておく。

  • 証明書ストアから証明書(PCCERT_CONTEXT)を取得する
    1. CertOpenStoreまたはCertOpenSystemStoreを呼び出す
    2. CertFindCertificateInStoreやCertEnumCertificateInStoreで証明書を取得
    3. PCCERT_CONTEXTを破棄するにはCertFreeCertificateContext
    4. HCERTSTOREを破棄するにはCertCloseStore
  • 証明書からクリデンシャル(PCredHandle)を取得する
    1. アルゴリズムとかフラグをいっぱい指定してAcquireCredentialsHandleを呼び出す
    2. 破棄するときはFreeCredentialHandleを使う