protected void processCertificateVerify(
      ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
      throws IOException {
    ByteArrayInputStream buf = new ByteArrayInputStream(body);

    DigitallySigned clientCertificateVerify = DigitallySigned.parse(state.serverContext, buf);

    TlsProtocol.assertEmpty(buf);

    // Verify the CertificateVerify message contains a correct signature.
    try {
      // TODO For TLS 1.2, this needs to be the hash specified in the DigitallySigned
      byte[] certificateVerifyHash =
          TlsProtocol.getCurrentPRFHash(state.serverContext, prepareFinishHash, null);

      org.bouncycastle.asn1.x509.Certificate x509Cert = state.clientCertificate.getCertificateAt(0);
      SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
      AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyInfo);

      TlsSigner tlsSigner = TlsUtils.createTlsSigner(state.clientCertificateType);
      tlsSigner.init(state.serverContext);
      tlsSigner.verifyRawSignature(
          clientCertificateVerify.getAlgorithm(),
          clientCertificateVerify.getSignature(),
          publicKey,
          certificateVerifyHash);
    } catch (Exception e) {
      throw new TlsFatalAlert(AlertDescription.decrypt_error);
    }
  }
  public void processServerCertificate(Certificate serverCertificate) throws IOException {
    X509CertificateStructure x509Cert = serverCertificate.certs[0];
    SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();

    try {
      this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
    } catch (RuntimeException e) {
      throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
    }

    if (tlsSigner == null) {
      try {
        this.dhAgreeServerPublicKey =
            validateDHPublicKey((DHPublicKeyParameters) this.serverPublicKey);
      } catch (ClassCastException e) {
        throw new TlsFatalAlert(AlertDescription.certificate_unknown);
      }

      TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyAgreement);
    } else {
      if (!tlsSigner.isValidPublicKey(this.serverPublicKey)) {
        throw new TlsFatalAlert(AlertDescription.certificate_unknown);
      }

      TlsUtils.validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
    }

    // TODO
    /*
     * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
     * signing algorithm for the certificate must be the same as the algorithm for the
     * certificate key."
     */
  }
  /**
   * Extracts the <tt>PublicKey</tt> from the provided CSR.
   *
   * <p>This method will throw a {@link RuntimeException} if the JRE is missing the RSA algorithm,
   * which is a required algorithm as defined by the JCA.
   *
   * @param csr the CSR to extract from.
   * @return the extracted <tt>PublicKey</tt>
   * @throws InvalidKeySpecException if the CSR is not using an RSA key.
   * @throws IOException if there is an error extracting the <tt>PublicKey</tt> parameters.
   */
  public static PublicKey getPublicKey(final PKCS10CertificationRequest csr)
      throws InvalidKeySpecException, IOException {
    SubjectPublicKeyInfo pubKeyInfo = csr.getSubjectPublicKeyInfo();
    RSAKeyParameters keyParams = (RSAKeyParameters) PublicKeyFactory.createKey(pubKeyInfo);
    KeySpec keySpec = new RSAPublicKeySpec(keyParams.getModulus(), keyParams.getExponent());

    KeyFactory kf;
    try {
      kf = KeyFactory.getInstance("RSA");
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    }
    return kf.generatePublic(keySpec);
  }
  public static void testGenP12() throws Exception {

    String rootCerBase64 =
        "MIIDvTCCAqWgAwIBAgIEEioP6zANBgkqhkiG9w0BAQsFADCBjjELMAkGA1UEBhMC"
            + "Q04xETAPBgNVBAgTCHNoYW5naGFpMREwDwYDVQQHEwhzaGFuZ2hhaTEzMDEGA1UE"
            + "Cgwq5LiK5rW36YeR6bm/6YeR6J6N5L+h5oGv5pyN5Yqh5pyJ6ZmQ5YWs5Y+4MQsw"
            + "CQYDVQQLEwJJVDEXMBUGA1UEAxMOb3Blbi5qbGZleC5jb20wHhcNMTQwODIxMDM0"
            + "NTQ5WhcNMjQwODE4MDM0NTQ5WjCBjjELMAkGA1UEBhMCQ04xETAPBgNVBAgTCHNo"
            + "YW5naGFpMREwDwYDVQQHEwhzaGFuZ2hhaTEzMDEGA1UECgwq5LiK5rW36YeR6bm/"
            + "6YeR6J6N5L+h5oGv5pyN5Yqh5pyJ6ZmQ5YWs5Y+4MQswCQYDVQQLEwJJVDEXMBUG"
            + "A1UEAxMOb3Blbi5qbGZleC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK"
            + "AoIBAQCQ4q4Yh8EPHbAP+BMiystXOEV56OE+IUwxSS7fRZ3ZrIEPImpnCiAe1txZ"
            + "vk0Lgv8ZWqrj4ErOT5FoOWfQW6Vva1DOXknCzFbypJMjqVnIS1/OwB64sYg4naLc"
            + "mM95GAHtEv9qxIWLbPhoLShz54znRNbM7mZJyT4BwLhKuKmfdo3UEuXvcoUFLN2l"
            + "f2wiTNmgMgpxcnCsWAx2nJaonPGCVXeQu0PXCVmCTyUUCWdT7P1io5yEpuRP/Dac"
            + "//g7Em8rkulgeO7e3gnEbrgrczsr2H1KJLTBjQmyWeWZg7LRYML6oHODrrDb0x++"
            + "yDT01p2BJHlvw/UzJq3I/CCci0lFAgMBAAGjITAfMB0GA1UdDgQWBBS1Lo57VqvU"
            + "BnfyJu51JO9csLJenjANBgkqhkiG9w0BAQsFAAOCAQEACcfPaVl5PIkBZ6cXyHuj"
            + "rJZkZH7Koqhx12DNeCoohdQkRda/gWeHVPsO7snK63sFhoY08OGVgvTRhgzwSBxJ"
            + "cx9GkCyojfHo5xZoOlSQ01PygyScd42DlseNiwXZGBfoxacLEYkIP6OXrDa+wNAP"
            + "gHnLI+37tzkafoPT0xoV/E9thvUUKX1jSIL5UCoGuso6FWLiZgDxD8wKgd22FcYo"
            + "T7B7DHG4R+0rgav81J9xjgOR3ayvNrb86iVvVBmrIiM7Gc2hf5PMiiAOaISST2cJ"
            + "x90X7TUA/f0qrYKveTvkRT77nLfzHV1a+PTS7PwkCXUt/NRm4VwseyGIgQ4FXH6W"
            + "zw==";

    // 解析root CA 证书
    X509Certificate rootcaCertificate =
        CertificateCoder.getX509Certificate(Base64.decodeBase64(rootCerBase64));
    // 解析root CA 私钥
    String rootcaDer = FileUtils.readFileToString(new File("d:\\rootcakey.pem"), "UTF-8");
    PrivateKey rootcaPrivateKey = PKCSCertificateCoder.getPrivateKeyFromPem(rootcaDer, "");
    System.out.println(rootcaPrivateKey);

    // 1.生成用户密钥对
    Security.addProvider(new BouncyCastleProvider());
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
    kpg.initialize(2048);
    KeyPair kp = kpg.genKeyPair();

    // 2.生成用户证书请求
    PKCS10CertificationRequest p10 = genPKCS10(kp);
    SubjectPublicKeyInfo subPublicKeyInfo = p10.getSubjectPublicKeyInfo();
    RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(subPublicKeyInfo);
    RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey publicKey = kf.generatePublic(rsaSpec);

    // 3.生成用户证书
    X509Certificate clientCertificate =
        buildEndEntityCert(publicKey, rootcaPrivateKey, rootcaCertificate);
    FileUtils.writeByteArrayToFile(new File("d:\\client.cer"), clientCertificate.getEncoded());

    // 4.生成用户p12文件
    storeP12(
        kp,
        new X509Certificate[] {clientCertificate, rootcaCertificate},
        "d:\\client.p12",
        "123456");

    FileOutputStream fos = new FileOutputStream(new File("d:\\client1.p12"));
    X509Certificate[] chain =
        new X509Certificate[] {rootcaCertificate, clientCertificate, clientCertificate};
    genPKCS12File(fos, kp.getPrivate(), chain);
  }