865 lines
31 KiB
Java
865 lines
31 KiB
Java
/* WolfSSLCertRequest.java
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
package com.wolfssl;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.nio.charset.Charset;
|
|
import java.security.PublicKey;
|
|
import java.security.PrivateKey;
|
|
import java.security.interfaces.RSAPublicKey;
|
|
import java.security.interfaces.RSAPrivateKey;
|
|
import java.security.interfaces.ECPublicKey;
|
|
import java.security.interfaces.ECPrivateKey;
|
|
|
|
/**
|
|
* WolfSSLCertRequest class, wraps native X509_REQ functionality.
|
|
*/
|
|
public class WolfSSLCertRequest {
|
|
|
|
private boolean active = false;
|
|
|
|
/* native X509_REQ pointer */
|
|
private long x509ReqPtr = 0;
|
|
|
|
/* lock around active state */
|
|
private final Object stateLock = new Object();
|
|
|
|
/* lock around native X509_REQ pointer use */
|
|
private final Object x509ReqLock = new Object();
|
|
|
|
/* Public key types used for CSR, mirrored from
|
|
* native enum in wolfssl/openssl/evp.h */
|
|
private static final int EVP_PKEY_RSA = 16;
|
|
private static final int EVP_PKEY_EC = 18;
|
|
|
|
/* Define from <wolfssl/openssl/asn1.h> */
|
|
private static final int MBSTRING_ASC = 0x1001;
|
|
|
|
/* Native JNI methods */
|
|
static native long X509_REQ_new();
|
|
static native void X509_REQ_free(long x509ReqPtr);
|
|
static native int X509_REQ_set_subject_name(long x509ReqPtr,
|
|
long x509NamePtr);
|
|
static native int X509_REQ_add1_attr_by_NID(long x509ReqPtr, int nid,
|
|
int type, byte[] bytes);
|
|
static native int X509_REQ_set_version(long x509ReqPtr, long ver);
|
|
static native byte[] X509_REQ_print(long x509ReqPtr);
|
|
static native int X509_REQ_sign(long x509ReqPtr, int evpKeyType,
|
|
byte[] keyBytes, int format, String digestAlg);
|
|
static native int X509_REQ_set_pubkey_native_open(long x509ReqPtr,
|
|
int keyType, byte[] fileBytes, int format);
|
|
static native byte[] X509_REQ_get_der(long x509);
|
|
static native byte[] X509_REQ_get_pem(long x509);
|
|
static native int X509_add_ext_via_nconf_nid(long x509Ptr, int nid,
|
|
String extValue, boolean isCritical);
|
|
static native int X509_add_ext_via_set_object_boolean(long x509Ptr,
|
|
int nid, boolean extValue, boolean isCritical, int pathLen);
|
|
|
|
/**
|
|
* Create new empty WolfSSLCertRequest object, for use with CSR generation
|
|
*
|
|
* @throws WolfSSLException if native API call fails.
|
|
*/
|
|
public WolfSSLCertRequest() throws WolfSSLException {
|
|
|
|
x509ReqPtr = X509_REQ_new();
|
|
if (x509ReqPtr == 0) {
|
|
throw new WolfSSLException("Failed to create WolfSSLCertRequest");
|
|
}
|
|
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, x509ReqPtr,
|
|
() -> "creating new WolfSSLCertRequest");
|
|
|
|
synchronized (stateLock) {
|
|
this.active = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the current WolfSSLCertRequest object is active.
|
|
*
|
|
* @throws IllegalStateException if object has been freed
|
|
*/
|
|
private void confirmObjectIsActive()
|
|
throws IllegalStateException {
|
|
|
|
synchronized (stateLock) {
|
|
if (this.active == false) {
|
|
throw new IllegalStateException(
|
|
"WolfSSLCertRequest object has been freed");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the Subject Name to be used with this WolfSSLCertRequest.
|
|
* Note that the WolfSSLX509Name object should be completely set up
|
|
* before calling this method. This method copies/duplicates the contents
|
|
* of the WOLFSSL_X509_NAME (WolfSSLX509Name) into the native
|
|
* WOLFSSL_X509 structure.
|
|
*
|
|
* @param name Initialized and populated WolfSSLX509 name to be set into
|
|
* Subject Name of WolfSSLCertRequest for cert generation.
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if native JNI error occurs.
|
|
*/
|
|
public void setSubjectName(WolfSSLX509Name name)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered setSubjectName(" + name + ")");
|
|
|
|
/* TODO somehow lock WolfSSLX509Name object while using pointer? */
|
|
ret = X509_REQ_set_subject_name(this.x509ReqPtr,
|
|
name.getNativeX509NamePtr());
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error setting subject name (ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a CSR attribute to this WolfSSLCertRequest
|
|
*
|
|
* @param nid NID of an attribute to add. Must be one of:
|
|
* WolfSSL.NID_pkcs9_challengePassword
|
|
* WolfSSL.NID_serialNumber
|
|
* WolfSSL.NID_pkcs9_unstructuredName
|
|
* WolfSSL.NID_pkcs9_contentType
|
|
* WolfSSL.NID_surname
|
|
* WolfSSL.NID_initials
|
|
* WolfSSL.NID_givenName
|
|
* WolfSSL.NID_dnQualifier
|
|
* @param value value of attribute to set, if passing in String, use
|
|
* String.getBytes()
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if native JNI error occurs.
|
|
*/
|
|
public void addAttribute(int nid, byte[] value)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered addAttribute(nid: " + nid + ", byte[])");
|
|
}
|
|
|
|
if (nid != WolfSSL.NID_pkcs9_challengePassword &&
|
|
nid != WolfSSL.NID_serialNumber &&
|
|
nid != WolfSSL.NID_pkcs9_unstructuredName &&
|
|
nid != WolfSSL.NID_pkcs9_contentType &&
|
|
nid != WolfSSL.NID_surname &&
|
|
nid != WolfSSL.NID_initials &&
|
|
nid != WolfSSL.NID_givenName &&
|
|
nid != WolfSSL.NID_dnQualifier) {
|
|
throw new WolfSSLException(
|
|
"Unsupported CSR attribute NID: " + nid);
|
|
}
|
|
|
|
if (value == null || value.length == 0) {
|
|
throw new WolfSSLException(
|
|
"CSR attribute value may not be null or zero length");
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_REQ_add1_attr_by_NID(this.x509ReqPtr, nid,
|
|
MBSTRING_ASC, value);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error setting CSR attribute (ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set CSR version for this WolfSSLCertRequest object.
|
|
*
|
|
* Calling this method is optional when generating a CSR. By default,
|
|
* a value of 0 (zero) is used for the CSR version. This is currently
|
|
* the version used by all CSR RFCs/specs.
|
|
*
|
|
* @param version version to set for CSR
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if native JNI error occurs.
|
|
*/
|
|
public void setVersion(long version)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered setVersion(" + version + ")");
|
|
|
|
ret = X509_REQ_set_version(this.x509ReqPtr, version);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error setting CSR version (ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set public key for this WolfSSLCertRequest, used when generating
|
|
* Certificate Signing Requests
|
|
*
|
|
* @param filePath Path to public key file
|
|
* @param keyType Type of public key algorithm, options are:
|
|
* WolfSSL.RSAk
|
|
* WolfSSL.ECDSAk
|
|
* @param format Format of public key file, options are:
|
|
* WolfSSL.SSL_FILETYPE_ASN1 (DER formatted)
|
|
* WolfSSL.SSL_FILETYPE_PEM (PEM formatted)
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws IOException on error opening input file
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void setPublicKey(String filePath, int keyType, int format)
|
|
throws IllegalStateException, IOException, WolfSSLException {
|
|
|
|
File keyFile = null;
|
|
byte[] fileBytes = null;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered setPublicKey(" + filePath + ", type: " +
|
|
keyType + ", format: " + format + ")");
|
|
}
|
|
|
|
if (filePath == null || filePath.isEmpty()) {
|
|
throw new WolfSSLException("File path is null or empty");
|
|
}
|
|
|
|
keyFile = new File(filePath);
|
|
if (!keyFile.exists()) {
|
|
throw new WolfSSLException(
|
|
"Input file does not exist: " + filePath);
|
|
}
|
|
|
|
fileBytes = WolfSSL.fileToBytes(keyFile);
|
|
if (fileBytes == null) {
|
|
throw new WolfSSLException(
|
|
"Failed to read bytes from file: " + filePath);
|
|
}
|
|
|
|
setPublicKey(fileBytes, keyType, format);
|
|
}
|
|
|
|
/**
|
|
* Set public key for this WolfSSLCertRequest, used when generating
|
|
* Certificate Signing Requests
|
|
*
|
|
* @param key Byte array containing public key
|
|
* @param keyType Type of public key algorithm, options are:
|
|
* WolfSSL.RSAk
|
|
* WolfSSL.ECDSAk
|
|
* @param format Format of public key file, options are:
|
|
* WolfSSL.SSL_FILETYPE_ASN1 (DER formatted)
|
|
* WolfSSL.SSL_FILETYPE_PEM (PEM formatted)
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws IOException on error opening input file
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void setPublicKey(byte[] key, int keyType, int format)
|
|
throws IllegalStateException, IOException, WolfSSLException {
|
|
|
|
int ret = 0;
|
|
int evpKeyType;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered setPublicKey(byte[], type: " + keyType +
|
|
", format: " + format + ")");
|
|
}
|
|
|
|
if (key == null || key.length == 0) {
|
|
throw new WolfSSLException("Key array is null or empty");
|
|
}
|
|
|
|
if (format != WolfSSL.SSL_FILETYPE_ASN1 &&
|
|
format != WolfSSL.SSL_FILETYPE_PEM) {
|
|
throw new WolfSSLException(
|
|
"Invalid key format, must be PEM or DER");
|
|
}
|
|
|
|
if (keyType == WolfSSL.RSAk) {
|
|
evpKeyType = EVP_PKEY_RSA;
|
|
} else if (keyType == WolfSSL.ECDSAk) {
|
|
evpKeyType = EVP_PKEY_EC;
|
|
} else {
|
|
throw new WolfSSLException("Unsupported public key type");
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_REQ_set_pubkey_native_open(this.x509ReqPtr, evpKeyType,
|
|
key, format);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error setting public key into native WOLFSSL_X509_REQ " +
|
|
"(ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set public key for this WolfSSLCertRequest, used when generating
|
|
* Certificate Signing Requests
|
|
*
|
|
* @param key PublicKey object containing public key to be used when
|
|
* generating CSR.
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
* @throws IOException on error opening/reading public key
|
|
*/
|
|
public void setPublicKey(PublicKey key)
|
|
throws IllegalStateException, IOException, WolfSSLException {
|
|
|
|
int keyType;
|
|
byte[] encodedKey = null;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered setPublicKey(" + key + ")");
|
|
}
|
|
|
|
if (key instanceof RSAPublicKey) {
|
|
keyType = WolfSSL.RSAk;
|
|
}
|
|
else if (key instanceof ECPublicKey) {
|
|
keyType = WolfSSL.ECDSAk;
|
|
}
|
|
else {
|
|
throw new WolfSSLException(
|
|
"PublicKey must be of type RSAPublicKey or ECPublicKey");
|
|
}
|
|
|
|
/* Get DER encoded key */
|
|
encodedKey = key.getEncoded();
|
|
if (encodedKey == null) {
|
|
throw new WolfSSLException(
|
|
"Error getting encoded (DER) format of PublicKey");
|
|
}
|
|
|
|
setPublicKey(encodedKey, keyType, WolfSSL.SSL_FILETYPE_ASN1);
|
|
}
|
|
|
|
/**
|
|
* Add an extension to a WolfSSLCertRequest given the NID and extension
|
|
* value String.
|
|
*
|
|
* This method supports the following extensions:
|
|
* - Key Usage (WolfSSL.NID_key_usage)
|
|
* - Extended Key Usage (WolfSSL.NID_ext_key_usage)
|
|
* - Subject Alt Name (WolfSSL.NED_subject_alt_name)
|
|
*
|
|
* @param nid NID of extension to add. Must be one of:
|
|
* WolfSSL.NID_key_usage
|
|
* WolfSSL.NID_ext_key_usage
|
|
* WolfSSL.NID_subject_alt_name
|
|
* @param value String value of extension to set. For keyUsage and
|
|
* extKeyUsage this should be a comma-delimited list.
|
|
* For subjectAltName, this is a single value. Possible
|
|
* values for keyUsage and extKeyUsage are:
|
|
*
|
|
* NID_key_usage:
|
|
* digitalSignature
|
|
* nonRepudiation
|
|
* contentCommitment
|
|
* keyEncipherment
|
|
* dataEncipherment
|
|
* keyAgreement
|
|
* keyCertSign
|
|
* cRLSign
|
|
* encipherOnly
|
|
* decipherOnly
|
|
*
|
|
* NID_ext_key_usage:
|
|
* serverAuth
|
|
* clientAuth
|
|
* codeSigning
|
|
* emailProtection
|
|
* timeStamping
|
|
* OCSPSigning
|
|
*
|
|
* @param isCritical Boolean flag indicating if this extension is
|
|
* critical
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void addExtension(int nid, String value, boolean isCritical)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret = 0;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered addExtension(nid: " + nid + ", value: " + value +
|
|
", isCritical: " + isCritical + ")");
|
|
}
|
|
|
|
if (nid != WolfSSL.NID_key_usage &&
|
|
nid != WolfSSL.NID_subject_alt_name &&
|
|
nid != WolfSSL.NID_ext_key_usage) {
|
|
throw new WolfSSLException(
|
|
"Unsupported X509v3 extension NID: " + nid);
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_add_ext_via_nconf_nid(this.x509ReqPtr, nid, value,
|
|
isCritical);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
if ((WolfSSL.getLibVersionHex() <= 0x05006003) &&
|
|
(nid == WolfSSL.NID_key_usage ||
|
|
nid == WolfSSL.NID_ext_key_usage)) {
|
|
|
|
/* wolfSSL versions 5.6.3 and earlier did not include code
|
|
* fixes to native wolfSSL allowing this extension support to
|
|
* work. Use a version > 5.6.3 or apply patch from wolfSSL
|
|
* PR 6585 for correct support */
|
|
throw new WolfSSLException(
|
|
"Error setting extension into native WOLFSSL_X509 " +
|
|
"(ret: " + ret + ").\nNeed to use wolfSSL version " +
|
|
"greater than 5.6.3 for extension support (PR 6585).");
|
|
}
|
|
|
|
throw new WolfSSLException(
|
|
"Error setting extension into native WOLFSSL_X509 " +
|
|
"(ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add an extension to a WolfSSLCertRequest given the NID and extension
|
|
* value true/false value.
|
|
*
|
|
* This method supports the following extensions:
|
|
* - Basic Constraints (WolfSSL.NID_basic_constraints)
|
|
*
|
|
* @param nid NID of extension to add. Must be one of:
|
|
* WolfSSL.NID_basic_constraints
|
|
* @param value Boolean value of extension (true/false)
|
|
* @param isCritical Boolean flag indicating if this extension is
|
|
* critical
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void addExtension(int nid, boolean value, boolean isCritical)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
addExtension(nid, value, -1, isCritical);
|
|
}
|
|
|
|
/**
|
|
* Add Basic Constraints extension with CA flag and path length constraint
|
|
* to a WolfSSLCertRequest.
|
|
*
|
|
* This method allows setting the Basic Constraints extension with both the
|
|
* CA boolean and an optional path length constraint. The path length limits
|
|
* the number of intermediate CA certificates that may follow this
|
|
* certificate in a valid certification path.
|
|
*
|
|
* To set Basic Constraints without a path length constraint, use
|
|
* {@link #addExtension(int, boolean, boolean)} with
|
|
* {@code WolfSSL.NID_basic_constraints} instead.
|
|
*
|
|
* @param nid NID of extension to add. Must be:
|
|
* WolfSSL.NID_basic_constraints
|
|
* @param value Boolean value of CA flag (true for CA, false for end entity)
|
|
* @param pathLen Maximum number of intermediate CA certificates allowed
|
|
* below this CA. Must be >= 0, or -1 to not set a path length
|
|
* constraint. Only meaningful when value is true.
|
|
* @param isCritical Boolean flag indicating if this extension is critical
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed
|
|
* @throws WolfSSLException if invalid arguments or on native JNI error
|
|
*/
|
|
public void addExtension(int nid, boolean value, int pathLen,
|
|
boolean isCritical) throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret = 0;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered addExtension(nid: " + nid + ", value: " + value +
|
|
", pathLen: " + pathLen + ", isCritical: " + isCritical + ")");
|
|
}
|
|
|
|
if (nid != WolfSSL.NID_basic_constraints) {
|
|
throw new WolfSSLException(
|
|
"Unsupported X509v3 extension NID: " + nid);
|
|
}
|
|
|
|
if (pathLen < -1) {
|
|
throw new WolfSSLException(
|
|
"Path length must be >= 0 or -1, got: " + pathLen);
|
|
}
|
|
|
|
if (!value && pathLen >= 0) {
|
|
throw new WolfSSLException(
|
|
"pathLen must not be set when isCA is FALSE (RFC 5280), " +
|
|
"got pathLen: " + pathLen);
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_add_ext_via_set_object_boolean(this.x509ReqPtr, nid,
|
|
value, isCritical, pathLen);
|
|
}
|
|
|
|
if (ret == WolfSSL.NOT_COMPILED_IN) {
|
|
throw new WolfSSLException(
|
|
"addExtension NOT_COMPILED_IN, pathLen " +
|
|
"support requires wolfSSL > 5.8.4 or " +
|
|
"PR 9940 patch (ret: " + ret + ")");
|
|
}
|
|
else if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error setting extension into native WOLFSSL_X509 " +
|
|
"(ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sign certificate request with private key from file.
|
|
*
|
|
* @param filePath Path to private key file
|
|
* @param keyType Type of public key algorithm, options are:
|
|
* WolfSSL.RSAk
|
|
* WolfSSL.ECDSAk
|
|
* @param format Format of private key file, options are:
|
|
* WolfSSL.SSL_FILETYPE_ASN1 (DER formatted)
|
|
* WolfSSL.SSL_FILETYPE_PEM (PEM formatted)
|
|
* @param digestAlg Message digest algorithm to use for signature
|
|
* generation. Options include the following, but native algorithm
|
|
* must be compiled into wolfSSL to be available:
|
|
* "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384",
|
|
* "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512"
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws IOException on error opening input file
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void signRequest(String filePath, int keyType, int format,
|
|
String digestAlg) throws IllegalStateException, IOException,
|
|
WolfSSLException {
|
|
|
|
File keyFile = null;
|
|
byte[] fileBytes = null;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered signRequest(" + filePath + ", keyType: " +
|
|
keyType + ", format: " + format + ", digestAlg: " +
|
|
digestAlg + ")");
|
|
}
|
|
|
|
if (filePath == null || filePath.isEmpty()) {
|
|
throw new WolfSSLException("File path is null or empty");
|
|
}
|
|
|
|
keyFile = new File(filePath);
|
|
if (!keyFile.exists()) {
|
|
throw new WolfSSLException(
|
|
"Input file does not exist: " + filePath);
|
|
}
|
|
|
|
fileBytes = WolfSSL.fileToBytes(keyFile);
|
|
if (fileBytes == null) {
|
|
throw new WolfSSLException(
|
|
"Failed to read bytes from file: " + filePath);
|
|
}
|
|
|
|
signRequest(fileBytes, keyType, format, digestAlg);
|
|
}
|
|
|
|
/**
|
|
* Sign certificate request with private key from buffer.
|
|
*
|
|
* @param key Byte array containing private key
|
|
* @param keyType Type of public key algorithm, options are:
|
|
* WolfSSL.RSAk
|
|
* WolfSSL.ECDSAk
|
|
* @param format Format of private key file, options are:
|
|
* WolfSSL.SSL_FILETYPE_ASN1 (DER formatted)
|
|
* WolfSSL.SSL_FILETYPE_PEM (PEM formatted)
|
|
* @param digestAlg Message digest algorithm to use for signature
|
|
* generation. Options include the following, but native algorithm
|
|
* must be compiled into wolfSSL to be available:
|
|
* "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384",
|
|
* "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512"
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void signRequest(byte[] key, int keyType, int format,
|
|
String digestAlg) throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret = 0;
|
|
int evpKeyType;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered signRequest(byte[], keyType: " + keyType +
|
|
", format: " + format + ", digestAlg: " + digestAlg + ")");
|
|
}
|
|
|
|
if (key == null || key.length == 0) {
|
|
throw new WolfSSLException("Key array is null or empty");
|
|
}
|
|
|
|
if (format != WolfSSL.SSL_FILETYPE_ASN1 &&
|
|
format != WolfSSL.SSL_FILETYPE_PEM) {
|
|
throw new WolfSSLException(
|
|
"Invalid key format, must be PEM or DER");
|
|
}
|
|
|
|
if (keyType == WolfSSL.RSAk) {
|
|
evpKeyType = EVP_PKEY_RSA;
|
|
} else if (keyType == WolfSSL.ECDSAk) {
|
|
evpKeyType = EVP_PKEY_EC;
|
|
} else {
|
|
throw new WolfSSLException("Unsupported private key type");
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, key, format,
|
|
digestAlg);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error signing native X509_REQ (ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sign certificate request with private key from PrivateKey object.
|
|
*
|
|
* @param key java.security.PrivateKey object containing private key,
|
|
* must be of type RSAPrivateKey or ECPrivateKey
|
|
* @param digestAlg Message digest algorithm to use for signature
|
|
* generation. Options include the following, but native algorithm
|
|
* must be compiled into wolfSSL to be available:
|
|
* "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384",
|
|
* "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512"
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLException if invalid arguments or native JNI error occurs.
|
|
*/
|
|
public void signRequest(PrivateKey key, String digestAlg)
|
|
throws IllegalStateException, WolfSSLException {
|
|
|
|
int ret = 0;
|
|
int evpKeyType;
|
|
byte[] encodedKey = null;
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr,
|
|
() -> "entered signRequest(key: " + key + ", digestAlg: " +
|
|
digestAlg + ")");
|
|
}
|
|
|
|
if (key == null) {
|
|
throw new WolfSSLException("Key object is null");
|
|
}
|
|
|
|
if (key instanceof RSAPrivateKey) {
|
|
evpKeyType = EVP_PKEY_RSA;
|
|
}
|
|
else if (key instanceof ECPrivateKey) {
|
|
evpKeyType = EVP_PKEY_EC;
|
|
}
|
|
else {
|
|
throw new WolfSSLException(
|
|
"PrivateKey must be of type RSAPrivateKey or ECPrivateKey");
|
|
}
|
|
|
|
/* Get DER encoded key */
|
|
encodedKey = key.getEncoded();
|
|
if (encodedKey == null) {
|
|
throw new WolfSSLException("PrivateKey does not support encoding");
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, encodedKey,
|
|
WolfSSL.SSL_FILETYPE_ASN1, digestAlg);
|
|
}
|
|
|
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
|
throw new WolfSSLException(
|
|
"Error signing native X509_REQ (ret: " + ret + ")");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get ASN.1/DER encoding of this CSR, after signRequest() has been called.
|
|
*
|
|
* @return DER encoded array of CSR or null if not available.
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLJNIException if native JNI operation fails
|
|
*/
|
|
public byte[] getDer() throws IllegalStateException, WolfSSLJNIException {
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr, () -> "entered getDer()");
|
|
|
|
return X509_REQ_get_der(this.x509ReqPtr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get PEM encoding of this CSR, after signRequest() has been called.
|
|
*
|
|
* @return PEM encoded array of CSR or null if not available.
|
|
*
|
|
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
|
|
* @throws WolfSSLJNIException if native JNI operation fails
|
|
*/
|
|
public byte[] getPem() throws IllegalStateException, WolfSSLJNIException {
|
|
|
|
confirmObjectIsActive();
|
|
|
|
synchronized (x509ReqLock) {
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr, () -> "entered getPem()");
|
|
|
|
return X509_REQ_get_pem(this.x509ReqPtr);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
|
|
byte[] x509ReqText = null;
|
|
|
|
synchronized (stateLock) {
|
|
if (this.active == false) {
|
|
return super.toString();
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
x509ReqText = X509_REQ_print(this.x509ReqPtr);
|
|
}
|
|
if (x509ReqText != null) {
|
|
/* let Java do the modified UTF-8 conversion */
|
|
return new String(x509ReqText, Charset.forName("UTF-8"));
|
|
} else {
|
|
System.out.println("toString: x509ReqTest == null");
|
|
}
|
|
}
|
|
|
|
return super.toString();
|
|
}
|
|
|
|
/**
|
|
* Frees WolfSSLCertRequest native resources.
|
|
*/
|
|
public synchronized void free() {
|
|
|
|
synchronized (stateLock) {
|
|
|
|
if (this.active == false) {
|
|
/* already freed, just return */
|
|
return;
|
|
}
|
|
|
|
synchronized (x509ReqLock) {
|
|
|
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
WolfSSLDebug.INFO, this.x509ReqPtr, () -> "entered free()");
|
|
|
|
/* free native resources */
|
|
X509_REQ_free(this.x509ReqPtr);
|
|
|
|
/* free Java resources */
|
|
this.active = false;
|
|
this.x509ReqPtr = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
@Override
|
|
protected void finalize() throws Throwable
|
|
{
|
|
this.free();
|
|
super.finalize();
|
|
}
|
|
}
|
|
|