@@ -994,9 +994,14 @@ certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
994994certBuilder. addExtension(Extension . authorityKeyIdentifier, false ,
995995 extUtils. createAuthorityKeyIdentifier(issuerCert));
996996
997+ /* Add Basic Constraints (non-CA) */
997998certBuilder. addExtension(Extension . basicConstraints, true ,
998999 new BasicConstraints (false ));
9991000
1001+ /* Or for a CA certificate (isCA:true), with path length constraint of 0 */
1002+ /* certBuilder.addExtension(Extension.basicConstraints, true,
1003+ new BasicConstraints(0)); */
1004+
10001005certBuilder. addExtension(Extension . keyUsage, true ,
10011006 new KeyUsage (KeyUsage . digitalSignature | KeyUsage . keyEncipherment));
10021007
@@ -1048,14 +1053,15 @@ import java.util.Date;
10481053/* Load issuer certificate for setting issuer name and AKID */
10491054WolfSSLCertificate issuerWolfCert = null ;
10501055WolfSSLCertificate cert = null ;
1056+ WolfSSLX509Name subject = null ;
10511057try {
10521058 issuerWolfCert =
10531059 new WolfSSLCertificate (issuerCert. getEncoded());
10541060
10551061 /* Create empty certificate for generation */
10561062 cert = new WolfSSLCertificate ();
10571063 /* Set subject and issuer names */
1058- WolfSSLX509Name subject = new WolfSSLX509Name ();
1064+ subject = new WolfSSLX509Name ();
10591065 subject. setCommonName(" Example" );
10601066 cert. setSubjectName(subject);
10611067 cert. setIssuerName(issuerWolfCert);
@@ -1080,6 +1086,9 @@ try {
10801086 /* Basic Constraints (non-CA) */
10811087 cert. addExtension(WolfSSL . NID_basic_constraints , false , false );
10821088
1089+ /* Or for a CA certificate with pathLen constraint set to 0 */
1090+ /* cert.addExtension(WolfSSL.NID_basic_constraints, true, 0, true); */
1091+
10831092 /* Key Usage */
10841093 cert. addExtension(WolfSSL . NID_key_usage ,
10851094 " digitalSignature,keyEncipherment" , true );
@@ -1105,6 +1114,9 @@ try {
11051114 byte [] certPem = cert. getPem();
11061115
11071116} finally {
1117+ if (subject != null ) {
1118+ subject. free();
1119+ }
11081120 if (cert != null ) {
11091121 cert. free();
11101122 }
@@ -1127,6 +1139,7 @@ try {
11271139| Subject Key Identifier | ` extUtils.createSubjectKeyIdentifier(...) ` | ` setSubjectKeyIdEx() ` or ` setSubjectKeyId(byte[]) ` |
11281140| Authority Key Identifier | ` extUtils.createAuthorityKeyIdentifier(...) ` | ` setAuthorityKeyIdEx(WolfSSLCertificate) ` or ` setAuthorityKeyId(byte[]) ` |
11291141| Basic Constraints | ` new BasicConstraints(boolean) ` | ` addExtension(NID_basic_constraints, boolean, boolean) ` |
1142+ | Basic Constraints (CA + pathLen) | ` new BasicConstraints(int) ` | ` addExtension(NID_basic_constraints, boolean, int, boolean) ` |
11301143| Key Usage | ` new KeyUsage(int) ` | ` addExtension(NID_key_usage, String, boolean) ` |
11311144| Extended Key Usage | ` new ExtendedKeyUsage(KeyPurposeId[]) ` | ` addExtension(NID_ext_key_usage, String, boolean) ` |
11321145| SAN (IP address) | ` new GeneralName(iPAddress, ...) ` | ` addAltNameIP(String) ` |
@@ -1139,6 +1152,130 @@ try {
11391152| Get PEM encoding | Manual conversion needed | ` getPem() ` |
11401153| Free resources | Garbage collected | ` free() ` |
11411154
1155+ ### CA Certificate Generation with Path Length Constraint
1156+
1157+ A common Bouncy Castle pattern is generating a self-signed CA certificate
1158+ with a ` BasicConstraints ` path length constraint. In Bouncy Castle,
1159+ ` new BasicConstraints(int) ` creates a CA constraint where the integer argument
1160+ specifies the maximum number of intermediate CA certificates allowed below this
1161+ CA in a certification path. wolfSSL JNI supports this through an overloaded
1162+ ` addExtension() ` method that accepts a ` pathLen ` parameter.
1163+
1164+ #### Bouncy Castle Approach
1165+
1166+ ``` java
1167+ import org.bouncycastle.asn1.x509.BasicConstraints ;
1168+ import org.bouncycastle.asn1.x509.Extension ;
1169+ import org.bouncycastle.asn1.x509.ExtendedKeyUsage ;
1170+ import org.bouncycastle.asn1.x509.KeyPurposeId ;
1171+ import org.bouncycastle.asn1.x509.KeyUsage ;
1172+ import org.bouncycastle.asn1.x500.X500Name ;
1173+ import org.bouncycastle.asn1.x500.style.RFC4519Style ;
1174+ import org.bouncycastle.asn1.x509.SubjectKeyIdentifier ;
1175+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo ;
1176+ import org.bouncycastle.asn1.ASN1Encoding ;
1177+ import org.bouncycastle.cert.X509v3CertificateBuilder ;
1178+ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter ;
1179+ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder ;
1180+
1181+ KeyPair keyPair = keyPairGenerator. generateKeyPair();
1182+ SubjectPublicKeyInfo subPubKeyInfo =
1183+ SubjectPublicKeyInfo . getInstance(keyPair. getPublic(). getEncoded());
1184+
1185+ /* Compute Subject Key Identifier from public key hash */
1186+ SubjectKeyIdentifier ski = new SubjectKeyIdentifier (
1187+ MessageDigest . getInstance(" SHA-1" )
1188+ .digest(subPubKeyInfo. getPublicKeyData(). getBytes()));
1189+
1190+ /* Build extensions list */
1191+ KeyUsage keyUsage = new KeyUsage (
1192+ KeyUsage . digitalSignature | KeyUsage . cRLSign | KeyUsage . keyCertSign);
1193+
1194+ List<Extension > extensions = new ArrayList<> ();
1195+ extensions. add(new Extension (Extension . keyUsage, true ,
1196+ keyUsage. toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1197+ extensions. add(new Extension (Extension . extendedKeyUsage, false ,
1198+ new ExtendedKeyUsage (new KeyPurposeId []{
1199+ KeyPurposeId . id_kp_clientAuth,
1200+ KeyPurposeId . id_kp_serverAuth,
1201+ KeyPurposeId . id_kp_OCSPSigning})
1202+ .toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1203+
1204+ /* BasicConstraints(0) = CA true, pathLen 0 */
1205+ extensions. add(new Extension (Extension . basicConstraints, true ,
1206+ new BasicConstraints (0 ). toASN1Primitive()
1207+ .getEncoded(ASN1Encoding . DER )));
1208+
1209+ extensions. add(new Extension (Extension . subjectKeyIdentifier,
1210+ false , ski. toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1211+
1212+ /* Build and sign the certificate */
1213+ X500Name issuer = new X500Name (RFC4519Style . INSTANCE , subject);
1214+ X509v3CertificateBuilder builder =
1215+ new X509v3CertificateBuilder (
1216+ issuer, BigInteger . valueOf(System . currentTimeMillis()),
1217+ Date . from(startDate), Date . from(expiryDate),
1218+ issuer, subPubKeyInfo);
1219+ for (Extension ext : extensions) {
1220+ builder. addExtension(ext);
1221+ }
1222+ ContentSigner signer = new JcaContentSignerBuilder (" SHA512withRSA" )
1223+ .build(keyPair. getPrivate());
1224+ X509Certificate caCert = new JcaX509CertificateConverter ()
1225+ .getCertificate(builder. build(signer));
1226+ ```
1227+
1228+ #### wolfSSL Approach
1229+
1230+ ``` java
1231+ import com.wolfssl.WolfSSLCertificate ;
1232+ import com.wolfssl.WolfSSLX509Name ;
1233+ import com.wolfssl.WolfSSL ;
1234+
1235+ KeyPair keyPair = keyPairGenerator. generateKeyPair();
1236+
1237+ WolfSSLCertificate cert = new WolfSSLCertificate ();
1238+ WolfSSLX509Name subjectName = new WolfSSLX509Name ();
1239+ try {
1240+ /* Set subject name (self-signed: issuer = subject) */
1241+ subjectName. setCommonName(subject);
1242+ cert. setSubjectName(subjectName);
1243+
1244+ /* Set serial number and validity dates */
1245+ cert. setSerialNumber(BigInteger . valueOf(System . currentTimeMillis()));
1246+ cert. setNotBefore(Date . from(startDate));
1247+ cert. setNotAfter(Date . from(expiryDate));
1248+
1249+ /* Set public key */
1250+ cert. setPublicKey(keyPair. getPublic());
1251+
1252+ /* Subject Key Identifier (SHA-1 hash computed internally) */
1253+ cert. setSubjectKeyIdEx();
1254+
1255+ /* Key Usage (critical) */
1256+ cert. addExtension(WolfSSL . NID_key_usage ,
1257+ " digitalSignature,cRLSign,keyCertSign" , true );
1258+
1259+ /* Extended Key Usage */
1260+ cert. addExtension(WolfSSL . NID_ext_key_usage ,
1261+ " clientAuth,serverAuth,OCSPSigning" , false );
1262+
1263+ /* Basic Constraints: CA=true, pathLen=0 (critical)
1264+ * BC equivalent: new BasicConstraints(0) */
1265+ cert. addExtension(WolfSSL . NID_basic_constraints , true , 0 , true );
1266+
1267+ /* Sign (self-signed with own private key) */
1268+ cert. signCert(keyPair. getPrivate(), " SHA512" );
1269+
1270+ byte [] certDer = cert. getDer();
1271+ byte [] certPem = cert. getPem();
1272+
1273+ } finally {
1274+ subjectName. free();
1275+ cert. free();
1276+ }
1277+ ```
1278+
11421279## Certificate Verification with CertManager
11431280
11441281Bouncy Castle provides ` X509CertificateHolder ` and related classes for
0 commit comments