@@ -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
@@ -1080,6 +1085,9 @@ try {
10801085 /* Basic Constraints (non-CA) */
10811086 cert. addExtension(WolfSSL . NID_basic_constraints , false , false );
10821087
1088+ /* Or for a CA certificate with pathLen constraint set to 0 */
1089+ /* cert.addExtension(WolfSSL.NID_basic_constraints, true, 0, true); */
1090+
10831091 /* Key Usage */
10841092 cert. addExtension(WolfSSL . NID_key_usage ,
10851093 " digitalSignature,keyEncipherment" , true );
@@ -1127,6 +1135,7 @@ try {
11271135| Subject Key Identifier | ` extUtils.createSubjectKeyIdentifier(...) ` | ` setSubjectKeyIdEx() ` or ` setSubjectKeyId(byte[]) ` |
11281136| Authority Key Identifier | ` extUtils.createAuthorityKeyIdentifier(...) ` | ` setAuthorityKeyIdEx(WolfSSLCertificate) ` or ` setAuthorityKeyId(byte[]) ` |
11291137| Basic Constraints | ` new BasicConstraints(boolean) ` | ` addExtension(NID_basic_constraints, boolean, boolean) ` |
1138+ | Basic Constraints (CA + pathLen) | ` new BasicConstraints(int) ` | ` addExtension(NID_basic_constraints, boolean, int, boolean) ` |
11301139| Key Usage | ` new KeyUsage(int) ` | ` addExtension(NID_key_usage, String, boolean) ` |
11311140| Extended Key Usage | ` new ExtendedKeyUsage(KeyPurposeId[]) ` | ` addExtension(NID_ext_key_usage, String, boolean) ` |
11321141| SAN (IP address) | ` new GeneralName(iPAddress, ...) ` | ` addAltNameIP(String) ` |
@@ -1139,6 +1148,131 @@ try {
11391148| Get PEM encoding | Manual conversion needed | ` getPem() ` |
11401149| Free resources | Garbage collected | ` free() ` |
11411150
1151+ ### CA Certificate Generation with Path Length Constraint
1152+
1153+ A common Bouncy Castle pattern is generating a self-signed CA certificate
1154+ with a ` BasicConstraints ` path length constraint. In Bouncy Castle,
1155+ ` new BasicConstraints(int) ` creates a CA constraint where the integer argument
1156+ specifies the maximum number of intermediate CA certificates allowed below this
1157+ CA in a certification path. wolfSSL JNI supports this through an overloaded
1158+ ` addExtension() ` method that accepts a ` pathLen ` parameter.
1159+
1160+ #### Bouncy Castle Approach
1161+
1162+ ``` java
1163+ import org.bouncycastle.asn1.x509.BasicConstraints ;
1164+ import org.bouncycastle.asn1.x509.Extension ;
1165+ import org.bouncycastle.asn1.x509.ExtendedKeyUsage ;
1166+ import org.bouncycastle.asn1.x509.KeyPurposeId ;
1167+ import org.bouncycastle.asn1.x509.KeyUsage ;
1168+ import org.bouncycastle.asn1.x500.X500Name ;
1169+ import org.bouncycastle.asn1.x500.style.RFC4519Style ;
1170+ import org.bouncycastle.asn1.x509.SubjectKeyIdentifier ;
1171+ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo ;
1172+ import org.bouncycastle.asn1.ASN1Encoding ;
1173+ import org.bouncycastle.cert.X509v3CertificateBuilder ;
1174+ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter ;
1175+ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder ;
1176+
1177+ KeyPair keyPair = keyPairGenerator. generateKeyPair();
1178+ SubjectPublicKeyInfo subPubKeyInfo =
1179+ SubjectPublicKeyInfo . getInstance(keyPair. getPublic(). getEncoded());
1180+
1181+ /* Compute Subject Key Identifier from public key hash */
1182+ SubjectKeyIdentifier ski = new SubjectKeyIdentifier (
1183+ MessageDigest . getInstance(" SHA-1" )
1184+ .digest(subPubKeyInfo. getPublicKeyData(). getBytes()));
1185+
1186+ /* Build extensions list */
1187+ KeyUsage keyUsage = new KeyUsage (
1188+ KeyUsage . digitalSignature | KeyUsage . cRLSign | KeyUsage . keyCertSign);
1189+
1190+ List<Extension > extensions = new ArrayList<> ();
1191+ extensions. add(new Extension (Extension . keyUsage, true ,
1192+ keyUsage. toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1193+ extensions. add(new Extension (Extension . extendedKeyUsage, false ,
1194+ new ExtendedKeyUsage (new KeyPurposeId []{
1195+ KeyPurposeId . id_kp_clientAuth,
1196+ KeyPurposeId . id_kp_serverAuth,
1197+ KeyPurposeId . id_kp_OCSPSigning})
1198+ .toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1199+
1200+ /* BasicConstraints(0) = CA true, pathLen 0 */
1201+ extensions. add(new Extension (Extension . basicConstraints, true ,
1202+ new BasicConstraints (0 ). toASN1Primitive()
1203+ .getEncoded(ASN1Encoding . DER )));
1204+
1205+ extensions. add(new Extension (Extension . subjectKeyIdentifier,
1206+ false , ski. toASN1Primitive(). getEncoded(ASN1Encoding . DER )));
1207+
1208+ /* Build and sign the certificate */
1209+ X500Name issuer = new X500Name (RFC4519Style . INSTANCE , subject);
1210+ X509v3CertificateBuilder builder =
1211+ new X509v3CertificateBuilder (
1212+ issuer, BigInteger . valueOf(System . currentTimeMillis()),
1213+ Date . from(startDate), Date . from(expiryDate),
1214+ issuer, subPubKeyInfo);
1215+ for (Extension ext : extensions) {
1216+ builder. addExtension(ext);
1217+ }
1218+ ContentSigner signer = new JcaContentSignerBuilder (" SHA512withRSA" )
1219+ .build(keyPair. getPrivate());
1220+ X509Certificate caCert = new JcaX509CertificateConverter ()
1221+ .getCertificate(builder. build(signer));
1222+ ```
1223+
1224+ #### wolfSSL Approach
1225+
1226+ ``` java
1227+ import com.wolfssl.WolfSSLCertificate ;
1228+ import com.wolfssl.WolfSSLX509Name ;
1229+ import com.wolfssl.WolfSSL ;
1230+
1231+ KeyPair keyPair = keyPairGenerator. generateKeyPair();
1232+
1233+ WolfSSLCertificate cert = new WolfSSLCertificate ();
1234+ try {
1235+ /* Set subject name (self-signed: issuer = subject) */
1236+ WolfSSLX509Name subjectName = new WolfSSLX509Name ();
1237+ subjectName. setCommonName(subject);
1238+ cert. setSubjectName(subjectName);
1239+
1240+ /* Set serial number and validity dates */
1241+ cert. setSerialNumber(BigInteger . valueOf(System . currentTimeMillis()));
1242+ cert. setNotBefore(Date . from(startDate));
1243+ cert. setNotAfter(Date . from(expiryDate));
1244+
1245+ /* Set public key */
1246+ cert. setPublicKey(keyPair. getPublic());
1247+
1248+ /* Subject Key Identifier (SHA-1 hash computed internally) */
1249+ cert. setSubjectKeyIdEx();
1250+
1251+ /* Key Usage (critical) */
1252+ cert. addExtension(WolfSSL . NID_key_usage ,
1253+ " digitalSignature,cRLSign,keyCertSign" , true );
1254+
1255+ /* Extended Key Usage */
1256+ cert. addExtension(WolfSSL . NID_ext_key_usage ,
1257+ " clientAuth,serverAuth,OCSPSigning" , false );
1258+
1259+ /* Basic Constraints: CA=true, pathLen=0 (critical)
1260+ * BC equivalent: new BasicConstraints(0) */
1261+ cert. addExtension(WolfSSL . NID_basic_constraints , true , 0 , true );
1262+
1263+ /* Sign (self-signed with own private key) */
1264+ cert. signCert(keyPair. getPrivate(), " SHA512" );
1265+
1266+ byte [] certDer = cert. getDer();
1267+ byte [] certPem = cert. getPem();
1268+
1269+ subjectName. free();
1270+
1271+ } finally {
1272+ cert. free();
1273+ }
1274+ ```
1275+
11421276## Certificate Verification with CertManager
11431277
11441278Bouncy Castle provides ` X509CertificateHolder ` and related classes for
0 commit comments