扩展 java.security.cert.X509Certificate 的正确方法是什么?

What is the proper way to extend java.security.cert.X509Certificate?

扩展 Java 的 X509Certificate 以向其添加自定义函数的正确方法是什么?让我们看看这个:

public abstract class MyX509Certificate extends java.security.cert.X509Certificate {
    protected X509Certificate() {
        super();
    }
}

所以通常你只需从密钥库中获取证书并像这样转换它:

X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);

我正在尝试这样投射我的:

MyX509Certificate my = (MyX509Certificate) keystore.getCertificate(alias);

但我得到:

Exception in thread "main" java.lang.ClassCastException: sun.security.x509.X509CertImpl cannot be cast to ca.carillon.crypto.cert.MyX509Certificate

为什么?

如其他答案中所述,您不应尝试创建自己的 class。您应该使用另一个安全提供程序。


要回答您关于 为什么 的实际问题,您不能投射到 class 是有原因的。实例化对象不是 MyX509Certificate,因此无法转换。 class 只能转换为该类型。

例如:

public abstract class AbstractParentClass {
}

public class ChildClassA extends AbstractParentClass {
}

public class ChildClassB extends AbstractParentClass {
}

您现在可以实例化 ChildClassA 并将其分配给类型 AbstractParentClass 的变量,然后将其转换为 ChildClassA 变量

public static void main(String[] args){
    AbstractParentClass instance = new ChildClassA();
    ChildClassA sameInstance = (ChildClassA) instance;
}

不能做的是将它转换为不属于其class的class分类法。

AbstractParentClass instance = new ChildClassA();
// This is runtime error because ChildClassB is not a ChildClassA
ChildClassB sameInstance = (ChildClassB) instance;

因此,除非您自己实例化 class,否则您不是因为您是从密钥库中检索它,否则 class 不是 MyX509Certificate 类型.

错误消息说:

java.lang.ClassCastException: sun.security.x509.X509CertImpl cannot be cast to ca.carillon.crypto.cert.MyX509Certificate

基本上是说一种类型 (sun.security.x509.X509CertImpl) 不能转换为另一种类型 (你的 MyX509Certificate class)。

sun.security.x509.X509CertImpl 是一个 subclass of java.security.cert.X509Certificate 并且正在 return 由 keystore.getCertificate 方法编辑。

发生的事情是 X509Certificate 是一个 abstract class,而 keystore.getCertificate 将 return 是它的一个内部实现(一个子class)。并且这个 subclass 可以不同,这取决于您的环境(JVM、提供程序等)。在这种情况下,它是 returning a sun.security.x509.X509CertImpl - 你不会在任何地方看到这个 class 因为它在 JVM 内部,而且在大多数情况下你实际上不需要知道它.您只需要知道它是一个 X509Certificate.


当您创建 X509Certificate 的自己的子 class 时,层次结构将如下所示:

                   X509Certificate <- super class
                           |
         ------------------------------------- 
         |                                   |
sun.security.x509.X509CertImpl        MyX509Certificate  <- subclasses of X509Certificate

由 kesytore (X509CertImpl) 编辑的 class return 和您的自定义 class (MyX509Certificate) 都是子class X509Certificate.

的 es

当密钥库 return 是 X509CertImpl 时,可以将其转换为 X509Certificate(subclass 实例可以分配给带有 super 的变量class 的类型)。

但是如果你尝试这样做:

MyX509Certificate my = (MyX509Certificate) keystore.getCertificate(alias);

密钥库正在 returning X509CertImpl,这是 X509Certificate,但 不是 MyX509Certificate -您不能将 "sibling" class 转换为另一个。 X509CertImpl 只知道它的超级 class (X509Certificate),但不知道 MyX509Certificate.


如果您想向 X509Certificate 添加功能,也许扩展它不是最好的解决方案,您应该选择 "Composition over Inheritance" approach.

您可以创建一个 具有 一个 X509Certificate(又称 "a wrapper")的 class 并使用它添加功能:

public class MyCustomCertificate {

    // wraps a X509Certificate
    private X509Certificate cert;

    public MyCustomCertificate(X509Certificate cert) {
        this.cert = cert;
    }

    public void myCustomFunctionality1() {
        // do something with this.cert
    }

    public void myCustomFunctionality2() {
        // do something with this.cert
    }

    // and so on...
}

然后您使用由密钥库 return 编辑的证书创建此 class:

X509Certificate x509Cert = (X509Certificate) keystore.getCertificate(alias);
MyCustomCertificate myCert = new MyCustomCertificate(x509Cert);

X509Certificate 有很多未实现的方法,扩展它需要你实现它们(这是不值得做的,IMO)。相反,您可以使用由密钥库(已经实现所有这些方法)编辑的证书 return 并添加您想要的功能。


不过,如果你真的想扩展 X509Certificate,你可以将方法委托给包装证书:

public class MyCustomCertificate extends X509Certificate {

    // wraps a X509Certificate
    private X509Certificate cert;

    public MyCustomCertificate(X509Certificate cert) {
        this.cert = cert;
    }

    public void myCustomFunctionality1() {
        // do something with this.cert
    }

    public void myCustomFunctionality2() {
        // do something with this.cert
    }

    // delegate all X509Certificate methods to the wrapped certificate
    public PublicKey getPublicKey() {
        return this.cert.getPublicKey();
    }

    public Principal getSubjectDN() {
        return this.cert.getSubjectDN();
    }

    // and so on...
}