アプリのマスターキーをJwkSetで管理したい
SecKind.GenericPassword で保存する
- どうも SecKind.Key だと うまく行かない
const SecKind KIND = SecKind.GenericPassword;
public static readonly string SERVICE_NAME = "Auth.Touch";
マスターキーが存在したら削除する
- KeyChain Itemのクエリレコード
static readonly SecRecord KEYCHAIN_QUERY = new SecRecord (KIND) {
Service = SERVICE_NAME,
UseOperationPrompt = "Authenticate yourself.",
};
- 指定したKeyChain Itemを削除する
public override void Delete ()
{
Evaluate (SecKeyChain.Remove (KEYCHAIN_QUERY));
}
- Success以外だと例外を出す
public static void Evaluate(SecStatusCode code){
if (code != SecStatusCode.Success) {
throw new KeyChainException (code);
}
}
JOSE JwkSetをシリアライズして入れてみる
- JwkSet をシリアライズして、 SecRecordの Genericにぶち込む
- コメントにあるようにTouch IDで守りたいのであれば、SecAccessControll を設定する
- AccessControlを指定しないと、Touch IDのプロンプトでません
public static SecRecord ToKeyChainItem (
Jose.JwkSet jwkset,
SecAccessControl grant)
{
// if AccessControl is not specified,
// this security record is not protected by TouchID
return new SecRecord (KIND) {
Service = SERVICE_NAME,
Generic = NSData.FromString(jwkset.ToJson()),
UseNoAuthenticationUI = true,
AccessControl=grant,
};
}
- Touch ID 用のAccess Controlは以下で渡す事にします
static readonly SecAccessControl GRANT = new SecAccessControl (
SecAccessible.WhenPasscodeSetThisDeviceOnly,
SecAccessControlCreateFlags.UserPresence);
- 作成。Deleteの例外はItemNotFoundの場合、無視する。
public override Jose.JwkSet Create ()
{
try{
this.Delete ();
}catch(KeyChainException ex) {
if (ex.Code != SecStatusCode.ItemNotFound)
throw ex;
}
return this.Add (CreateJwkSet());
}
- Add
public Jose.JwkSet Add(Jose.JwkSet jwkset)
{
var kci = ToKeyChainItem(jwkset, GRANT);
Evaluate (SecKeyChain.Add (kci));
return jwkset;
}
- JwkSetはEC521で
public static Jose.JwkSet CreateJwkSet()
{
var jwk = Jose.Jwa.KeyDef.EC.GenerateKey (Jose.Jwa.Ec.CurveEnum.P_521);
jwk.kid = DateTime.Now.ToString (); // for TEST
return new Jose.JwkSet () {
keys = new System.Collections.Generic.List<Jose.Jwk>{ jwk }
};
}
参照する
- Deleteを同じKeyChain Itemをレコードして探す
- みつかったらJwkSetに復元する
public override Jose.JwkSet Load ()
{
SecStatusCode code;
SecRecord resultData = SecKeyChain.QueryAsRecord (
KEYCHAIN_QUERY, out code);
Evaluate(code);
return ToJwkSet(resultData.Generic);
}
動かす
- 起動
- 空で削除すると例外
- 新規作成 & 保存
- Browse すると Touch ID 認証
- 認証が通ると表示
- ちなみに“Enter Passcord”でパスコード認証も通ります
SecKind.Keyだとうまく行かない
- Touch ID を使わないと以下のコードで SecKind.Keyで保存できるが、 Touch IDプロテクトすると Param エラー
SecStatusCode code = SecKeyChain.Add ( new SecRecord ( SecKind.Key ) {
Service = _service_name,
Label = _service_name,
Account = _account_name,
Generic = NSData.FromString ( jwkset.ToJson(), NSStringEncoding.UTF8 ),
Accessible = accessible,
Synchronizable = sync
} );
- どのParamでエラーなのかがよくわからん