Hatena::ブログ(Diary)

noryksjの日記兼備忘録

2008-03-18

WAITFOR(RECEIVE)

ここによるとMS SQLServerでService Brokerからのメッセージを受信する際にWAITFOR(RECEIVE)を使用すると、分散トランザクションを使用できないみたいだ(WAITFORは内部でSAVEPOINTを使用しているらしい)。

こんな例外が発生する。

System.Transactions.TransactionAbortedException: トランザクションが中止されました。
 ---> System.Transactions.TransactionPromotionException: トランザクションを進めるときにエラーが発生しました。
 ---> System.Data.SqlClient.SqlException: このトランザクションを分散トランザクションに昇格できません。アクティブな savepoint がこのトランザクション内に存在します。
...

2007-11-22

JavaでeTokenを使う(その2)

まずは、eTokenでキーペアを作ってみる。providerとkeyStoreはすでに設定済みと言う前提で。

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Calendar;
import javax.crypto.Cipher;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateSubjectName;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;


...

public void doGenerateKeyPair(String alias, String principal, String storePass,
				int keyLength, BigInteger serial)
		throws Exception {
		
    KeyPairGenerator kpgen = KeyPairGenerator.getInstance("RSA", provider);
    kpgen.initialize(keyLength);
    KeyPair kp = kpgen.generateKeyPair();

    Calendar cal = Calendar.getInstance();
    Calendar expire = (Calendar)cal.clone();
    expire.add(Calendar.DATE, 3650);
		
    X509CertInfo info = new X509CertInfo();
		
    CertificateValidity validity =
            new CertificateValidity(cal.getTime(), expire.getTime());
    info.set(X509CertInfo.VALIDITY, validity);
    info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serial));

    X500Name name = new X500Name(principal);
    CertificateIssuerName issuer = new CertificateIssuerName(name);
    CertificateSubjectName subject = new CertificateSubjectName(name);
    AlgorithmId alogoId = AlgorithmId.get(
            AlgorithmId.sha1WithRSAEncryption_oid.toString());

    info.set(X509CertInfo.ISSUER, issuer);
    info.set(X509CertInfo.SUBJECT, subject);
    info.set(X509CertInfo.KEY, new CertificateX509Key(kp.getPublic()));
    info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(alogoId));

    X509CertImpl target = new X509CertImpl(info);
    target.sign(kp.getPrivate(), alogoId.getName(), provider.getName());

    keyStore.setKeyEntry(alias, (Key)kp.getPrivate(), storePass.toCharArray(),
                        new Certificate[] {target});
}

まず、以下の行でキーペアを作成する。eTokenで使用可能なのはキーはRSAなのでそれを指定する。キー長は1024ビット(eToken PRO 32k/64k)もしくは2048ビット(eToken PRO 64k)を指定する。ただし、2048ビットを指定するには、eToken PRO 64kの場合でも2048ビットRSAキーを使用できるようにeTokenが初期化されている必要がある。

KeyPairGenerator kpgen = KeyPairGenerator.getInstance("RSA", provider);
kpgen.initialize(keyLength);
KeyPair kp = kpgen.generateKeyPair();

次に、生成したキーペアの公開鍵に自己証明書を作成し、秘密鍵で署名する。ここで指定しているprincipalには、「CN=Common Name,OU=Your OU,U=Your U,C=JP」のような文字列を指定する。自己証明のため、ISSUERとSUBJECTには同じ名前が入る。

Calendar cal = Calendar.getInstance();
Calendar expire = (Calendar)cal.clone();
expire.add(Calendar.DATE, 3650);
		
X509CertInfo info = new X509CertInfo();
		
CertificateValidity validity =
        new CertificateValidity(cal.getTime(), expire.getTime());
info.set(X509CertInfo.VALIDITY, validity);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serial));

X500Name name = new X500Name(principal);
CertificateIssuerName issuer = new CertificateIssuerName(name);
CertificateSubjectName subject = new CertificateSubjectName(name);
AlgorithmId alogoId = AlgorithmId.get(
        AlgorithmId.sha1WithRSAEncryption_oid.toString());

info.set(X509CertInfo.ISSUER, issuer);
info.set(X509CertInfo.SUBJECT, subject);
info.set(X509CertInfo.KEY, new CertificateX509Key(kp.getPublic()));
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(alogoId));

X509CertImpl target = new X509CertImpl(info);
target.sign(kp.getPrivate(), alogoId.getName(), provider.getName());

最後にこれらをkeyStore(eToken)にセーブする。

keyStore.setKeyEntry(alias, (Key)kp.getPrivate(), storePass.toCharArray(),
                    new Certificate[] {target});

実行すると、eTokenのランプがチカチカするのでよくわかる。

2007-11-21

JavaでeTokenを使う(その1)

eTokenを使用するJavaのプログラムを作ってみる。eTokenを使用するには、eTokenを使用できるPKCS11のプロバイダーを経由して行う。たぶん。

import java.security.Provider;

public class AladdinTool {
    private static Provider provider;
    static {
        InputStream is = getConfigStream();
        try {
            provider = new sun.security.pkcs11.SunPKCS11(is);
            Security.addProvider(provider);
        }
        finally {
            try {
                is.close();
            }
            catch (Exception ex) {
            }
        }
    }
    private static InputStream getConfigStream() throws Exception {
        Map<String, String> env = System.getenv();
        String sysRoot = env.get("SystemRoot");
        String pkcsDll = null;
        if (sysRoot != null) {
            // Windows
            pkcsDll = sysRoot + "\\system32\\eTpkcs11.dll";
        }
        else {
            throw    new UnsupportedOperationException(
                            "This type of OS or JRE is not supported yet.");
        }
        String content =
                "library=" + pkcsDll + "\n" +
                "name=eToken\n" +
                "description=eToken PKCS#11 Dynamic Link Library\n" +
                "attributes=compatibility\n"
                ;
        return	new ByteArrayInputStream(content.getBytes());
    }
    public static KeyStore login(String pin) throws Exception {
        char[] pinarry = pin.toCharArray();
        KeyStore ks = KeyStore.getInstance("PKCS11", provider);
        ks.load(null, pin);
        return ks;
    }
}

面倒くさいので、getConfigStream()でeTokenのプロパティの内容を内部で作成するようにしてみた(Windowsでしか使えないけど)。内容はkeytoolでeTokenを使用するときに指定するプロパティファイルの中身と同じものとした。

後は、login()でパスワードを指定してKeyStoreを取得した後にエントリを取得すればいい。