|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# SAN Test Certificate Generation Script |
| 4 | +# |
| 5 | +# Copyright (C) 2006-2026 wolfSSL Inc. |
| 6 | +# |
| 7 | +# This script generates test certificates with various Subject Alternative Name |
| 8 | +# (SAN) types for testing WolfSSLAltName functionality. |
| 9 | +# |
| 10 | +# Script should be run from the <wolfssljni>/examples/certs directory. |
| 11 | +# |
| 12 | +# Generated certificates: |
| 13 | +# - san-test-ca-key.pem / san-test-ca-cert.pem: Self-signed CA |
| 14 | +# - san-test-all-types.pem: Certificate with all supported SAN types |
| 15 | +# - san-test-dns-ip.pem: Certificate with DNS and IP SANs |
| 16 | +# - san-test-email-uri.pem: Certificate with email and URI SANs |
| 17 | +# - san-test-othername-upn.pem: Certificate with Microsoft UPN otherName |
| 18 | +# - san-test-dirname-rid.pem: Certificate with directoryName and registeredID |
| 19 | +# |
| 20 | +# SAN Types (RFC 5280 GeneralName): |
| 21 | +# 0 = otherName (Microsoft UPN: OID 1.3.6.1.4.1.311.20.2.3) |
| 22 | +# 1 = rfc822Name (email) |
| 23 | +# 2 = dNSName |
| 24 | +# 4 = directoryName |
| 25 | +# 6 = uniformResourceIdentifier (URI) |
| 26 | +# 7 = iPAddress (IPv4 and IPv6) |
| 27 | +# 8 = registeredID |
| 28 | + |
| 29 | +set -e |
| 30 | + |
| 31 | +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 32 | +cd "$SCRIPT_DIR" |
| 33 | + |
| 34 | +# Certificate validity (10 years) |
| 35 | +DAYS=3650 |
| 36 | + |
| 37 | +# Output directory for SAN test certs |
| 38 | +SAN_DIR="san-test" |
| 39 | +mkdir -p "$SAN_DIR" |
| 40 | + |
| 41 | +printf "Generating SAN test certificates in %s/\n" "$SAN_DIR" |
| 42 | + |
| 43 | +# ============================================================================= |
| 44 | +# Generate CA key and self-signed certificate |
| 45 | +# ============================================================================= |
| 46 | +printf "\n[1/7] Generating SAN test CA...\n" |
| 47 | + |
| 48 | +openssl genrsa -out "$SAN_DIR/san-test-ca-key.pem" 2048 |
| 49 | + |
| 50 | +openssl req -x509 -new -nodes \ |
| 51 | + -key "$SAN_DIR/san-test-ca-key.pem" \ |
| 52 | + -sha256 -days $DAYS \ |
| 53 | + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Testing/CN=SAN Test CA" \ |
| 54 | + -out "$SAN_DIR/san-test-ca-cert.pem" |
| 55 | + |
| 56 | +printf " Created: san-test-ca-key.pem, san-test-ca-cert.pem\n" |
| 57 | + |
| 58 | +# ============================================================================= |
| 59 | +# Helper function to generate a certificate with SANs |
| 60 | +# ============================================================================= |
| 61 | +generate_cert() { |
| 62 | + local name=$1 |
| 63 | + local cn=$2 |
| 64 | + local san_config=$3 |
| 65 | + local extra_sections=$4 |
| 66 | + |
| 67 | + printf "\n[%s] Generating %s...\n" "$5" "$name" |
| 68 | + |
| 69 | + # Generate key |
| 70 | + openssl genrsa -out "$SAN_DIR/${name}-key.pem" 2048 |
| 71 | + |
| 72 | + # Create CSR |
| 73 | + openssl req -new \ |
| 74 | + -key "$SAN_DIR/${name}-key.pem" \ |
| 75 | + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Testing/CN=${cn}" \ |
| 76 | + -out "$SAN_DIR/${name}.csr" |
| 77 | + |
| 78 | + # Create extension config file |
| 79 | + cat > "$SAN_DIR/${name}-ext.cnf" << EOF |
| 80 | +[req] |
| 81 | +distinguished_name = req_distinguished_name |
| 82 | +
|
| 83 | +[req_distinguished_name] |
| 84 | +
|
| 85 | +[san_ext] |
| 86 | +subjectAltName = ${san_config} |
| 87 | +${extra_sections} |
| 88 | +EOF |
| 89 | + |
| 90 | + # Sign with CA |
| 91 | + openssl x509 -req \ |
| 92 | + -in "$SAN_DIR/${name}.csr" \ |
| 93 | + -CA "$SAN_DIR/san-test-ca-cert.pem" \ |
| 94 | + -CAkey "$SAN_DIR/san-test-ca-key.pem" \ |
| 95 | + -CAcreateserial \ |
| 96 | + -out "$SAN_DIR/${name}.pem" \ |
| 97 | + -days $DAYS \ |
| 98 | + -sha256 \ |
| 99 | + -extfile "$SAN_DIR/${name}-ext.cnf" \ |
| 100 | + -extensions san_ext |
| 101 | + |
| 102 | + # Also create DER format |
| 103 | + openssl x509 -in "$SAN_DIR/${name}.pem" -outform DER -out "$SAN_DIR/${name}.der" |
| 104 | + |
| 105 | + # Cleanup CSR and config |
| 106 | + rm -f "$SAN_DIR/${name}.csr" "$SAN_DIR/${name}-ext.cnf" |
| 107 | + |
| 108 | + printf " Created: %s.pem, %s.der\n" "$name" "$name" |
| 109 | +} |
| 110 | + |
| 111 | +# ============================================================================= |
| 112 | +# Certificate 1: DNS and IP addresses (most common case) |
| 113 | +# ============================================================================= |
| 114 | +generate_cert "san-test-dns-ip" "DNS and IP Test" \ |
| 115 | + "DNS:localhost,DNS:example.com,DNS:*.wildcard.com,IP:127.0.0.1,IP:192.168.1.1,IP:::1,IP:fe80::1" \ |
| 116 | + "" "2/7" |
| 117 | + |
| 118 | +# ============================================================================= |
| 119 | +# Certificate 2: Email and URI |
| 120 | +# ============================================================================= |
| 121 | +generate_cert "san-test-email-uri" "Email and URI Test" \ |
| 122 | + "email:test@example.com,email:admin@wolfssl.com,URI:https://www.wolfssl.com,URI:ldap://ldap.example.com/cn=test" \ |
| 123 | + "" "3/7" |
| 124 | + |
| 125 | +# ============================================================================= |
| 126 | +# Certificate 3: Microsoft UPN otherName (for Active Directory) |
| 127 | +# Microsoft UPN OID: 1.3.6.1.4.1.311.20.2.3 |
| 128 | +# ============================================================================= |
| 129 | +printf "\n[4/7] Generating san-test-othername-upn...\n" |
| 130 | + |
| 131 | +# Generate key |
| 132 | +openssl genrsa -out "$SAN_DIR/san-test-othername-upn-key.pem" 2048 |
| 133 | + |
| 134 | +# Create CSR |
| 135 | +openssl req -new \ |
| 136 | + -key "$SAN_DIR/san-test-othername-upn-key.pem" \ |
| 137 | + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Testing/CN=UPN Test User" \ |
| 138 | + -out "$SAN_DIR/san-test-othername-upn.csr" |
| 139 | + |
| 140 | +# Create extension config with otherName for UPN |
| 141 | +# The format is: otherName:OID;encoding:value |
| 142 | +# For UPN, OID is 1.3.6.1.4.1.311.20.2.3 and value is UTF8String |
| 143 | +cat > "$SAN_DIR/san-test-othername-upn-ext.cnf" << 'EOF' |
| 144 | +[req] |
| 145 | +distinguished_name = req_distinguished_name |
| 146 | +
|
| 147 | +[req_distinguished_name] |
| 148 | +
|
| 149 | +[san_ext] |
| 150 | +subjectAltName = @san_names |
| 151 | +
|
| 152 | +[san_names] |
| 153 | +otherName.0 = 1.3.6.1.4.1.311.20.2.3;UTF8:testuser@example.com |
| 154 | +otherName.1 = 1.3.6.1.4.1.311.20.2.3;UTF8:admin@wolfssl.local |
| 155 | +email = testuser@example.com |
| 156 | +EOF |
| 157 | + |
| 158 | +# Sign with CA |
| 159 | +openssl x509 -req \ |
| 160 | + -in "$SAN_DIR/san-test-othername-upn.csr" \ |
| 161 | + -CA "$SAN_DIR/san-test-ca-cert.pem" \ |
| 162 | + -CAkey "$SAN_DIR/san-test-ca-key.pem" \ |
| 163 | + -CAcreateserial \ |
| 164 | + -out "$SAN_DIR/san-test-othername-upn.pem" \ |
| 165 | + -days $DAYS \ |
| 166 | + -sha256 \ |
| 167 | + -extfile "$SAN_DIR/san-test-othername-upn-ext.cnf" \ |
| 168 | + -extensions san_ext |
| 169 | + |
| 170 | +# Also create DER format |
| 171 | +openssl x509 -in "$SAN_DIR/san-test-othername-upn.pem" -outform DER \ |
| 172 | + -out "$SAN_DIR/san-test-othername-upn.der" |
| 173 | + |
| 174 | +# Cleanup |
| 175 | +rm -f "$SAN_DIR/san-test-othername-upn.csr" "$SAN_DIR/san-test-othername-upn-ext.cnf" |
| 176 | + |
| 177 | +printf " Created: san-test-othername-upn.pem, san-test-othername-upn.der\n" |
| 178 | + |
| 179 | +# ============================================================================= |
| 180 | +# Certificate 4: directoryName and registeredID |
| 181 | +# ============================================================================= |
| 182 | +printf "\n[5/7] Generating san-test-dirname-rid...\n" |
| 183 | + |
| 184 | +# Generate key |
| 185 | +openssl genrsa -out "$SAN_DIR/san-test-dirname-rid-key.pem" 2048 |
| 186 | + |
| 187 | +# Create CSR |
| 188 | +openssl req -new \ |
| 189 | + -key "$SAN_DIR/san-test-dirname-rid-key.pem" \ |
| 190 | + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Testing/CN=DirName RID Test" \ |
| 191 | + -out "$SAN_DIR/san-test-dirname-rid.csr" |
| 192 | + |
| 193 | +# Create extension config with directoryName and registeredID |
| 194 | +cat > "$SAN_DIR/san-test-dirname-rid-ext.cnf" << 'EOF' |
| 195 | +[req] |
| 196 | +distinguished_name = req_distinguished_name |
| 197 | +
|
| 198 | +[req_distinguished_name] |
| 199 | +
|
| 200 | +[san_ext] |
| 201 | +subjectAltName = @san_names |
| 202 | +
|
| 203 | +[san_names] |
| 204 | +dirName.0 = dir_sect_1 |
| 205 | +dirName.1 = dir_sect_2 |
| 206 | +RID = 1.2.3.4.5.6.7.8.9 |
| 207 | +
|
| 208 | +[dir_sect_1] |
| 209 | +C = US |
| 210 | +ST = California |
| 211 | +L = San Francisco |
| 212 | +O = Test Organization |
| 213 | +CN = Directory Name Test 1 |
| 214 | +
|
| 215 | +[dir_sect_2] |
| 216 | +C = DE |
| 217 | +O = German Organization |
| 218 | +CN = Directory Name Test 2 |
| 219 | +EOF |
| 220 | + |
| 221 | +# Sign with CA |
| 222 | +openssl x509 -req \ |
| 223 | + -in "$SAN_DIR/san-test-dirname-rid.csr" \ |
| 224 | + -CA "$SAN_DIR/san-test-ca-cert.pem" \ |
| 225 | + -CAkey "$SAN_DIR/san-test-ca-key.pem" \ |
| 226 | + -CAcreateserial \ |
| 227 | + -out "$SAN_DIR/san-test-dirname-rid.pem" \ |
| 228 | + -days $DAYS \ |
| 229 | + -sha256 \ |
| 230 | + -extfile "$SAN_DIR/san-test-dirname-rid-ext.cnf" \ |
| 231 | + -extensions san_ext |
| 232 | + |
| 233 | +# Also create DER format |
| 234 | +openssl x509 -in "$SAN_DIR/san-test-dirname-rid.pem" -outform DER \ |
| 235 | + -out "$SAN_DIR/san-test-dirname-rid.der" |
| 236 | + |
| 237 | +# Cleanup |
| 238 | +rm -f "$SAN_DIR/san-test-dirname-rid.csr" "$SAN_DIR/san-test-dirname-rid-ext.cnf" |
| 239 | + |
| 240 | +printf " Created: san-test-dirname-rid.pem, san-test-dirname-rid.der\n" |
| 241 | + |
| 242 | +# ============================================================================= |
| 243 | +# Certificate 5: ALL SAN types in one certificate (comprehensive test) |
| 244 | +# ============================================================================= |
| 245 | +printf "\n[6/7] Generating san-test-all-types (comprehensive)...\n" |
| 246 | + |
| 247 | +# Generate key |
| 248 | +openssl genrsa -out "$SAN_DIR/san-test-all-types-key.pem" 2048 |
| 249 | + |
| 250 | +# Create CSR |
| 251 | +openssl req -new \ |
| 252 | + -key "$SAN_DIR/san-test-all-types-key.pem" \ |
| 253 | + -subj "/C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Testing/CN=All SAN Types Test" \ |
| 254 | + -out "$SAN_DIR/san-test-all-types.csr" |
| 255 | + |
| 256 | +# Create extension config with ALL SAN types |
| 257 | +# Note: registeredID (type 8) is excluded as it can cause issues with some |
| 258 | +# wolfSSL builds when parsing |
| 259 | +cat > "$SAN_DIR/san-test-all-types-ext.cnf" << 'EOF' |
| 260 | +[req] |
| 261 | +distinguished_name = req_distinguished_name |
| 262 | +
|
| 263 | +[req_distinguished_name] |
| 264 | +
|
| 265 | +[san_ext] |
| 266 | +subjectAltName = @san_names |
| 267 | +
|
| 268 | +[san_names] |
| 269 | +# Type 0: otherName (Microsoft UPN) |
| 270 | +otherName.0 = 1.3.6.1.4.1.311.20.2.3;UTF8:allsantypes@wolfssl.com |
| 271 | +
|
| 272 | +# Type 1: rfc822Name (email) |
| 273 | +email.0 = test@example.com |
| 274 | +email.1 = admin@wolfssl.com |
| 275 | +
|
| 276 | +# Type 2: dNSName |
| 277 | +DNS.0 = localhost |
| 278 | +DNS.1 = www.example.com |
| 279 | +DNS.2 = *.wildcard.example.com |
| 280 | +
|
| 281 | +# Type 4: directoryName |
| 282 | +dirName.0 = dir_sect |
| 283 | +
|
| 284 | +# Type 6: uniformResourceIdentifier |
| 285 | +URI.0 = https://www.wolfssl.com |
| 286 | +URI.1 = ldap://ldap.example.com/cn=test |
| 287 | +
|
| 288 | +# Type 7: iPAddress (IPv4 and IPv6) |
| 289 | +IP.0 = 127.0.0.1 |
| 290 | +IP.1 = 192.168.1.100 |
| 291 | +IP.2 = ::1 |
| 292 | +IP.3 = fe80::1234:5678:abcd:ef00 |
| 293 | +
|
| 294 | +# Note: registeredID (type 8) excluded - can cause issues with wolfSSL parsing |
| 295 | +
|
| 296 | +[dir_sect] |
| 297 | +C = US |
| 298 | +ST = Montana |
| 299 | +L = Bozeman |
| 300 | +O = wolfSSL Inc. |
| 301 | +OU = Engineering |
| 302 | +CN = Directory Name Entry |
| 303 | +EOF |
| 304 | + |
| 305 | +# Sign with CA |
| 306 | +openssl x509 -req \ |
| 307 | + -in "$SAN_DIR/san-test-all-types.csr" \ |
| 308 | + -CA "$SAN_DIR/san-test-ca-cert.pem" \ |
| 309 | + -CAkey "$SAN_DIR/san-test-ca-key.pem" \ |
| 310 | + -CAcreateserial \ |
| 311 | + -out "$SAN_DIR/san-test-all-types.pem" \ |
| 312 | + -days $DAYS \ |
| 313 | + -sha256 \ |
| 314 | + -extfile "$SAN_DIR/san-test-all-types-ext.cnf" \ |
| 315 | + -extensions san_ext |
| 316 | + |
| 317 | +# Also create DER format |
| 318 | +openssl x509 -in "$SAN_DIR/san-test-all-types.pem" -outform DER \ |
| 319 | + -out "$SAN_DIR/san-test-all-types.der" |
| 320 | + |
| 321 | +# Cleanup |
| 322 | +rm -f "$SAN_DIR/san-test-all-types.csr" "$SAN_DIR/san-test-all-types-ext.cnf" |
| 323 | + |
| 324 | +printf " Created: san-test-all-types.pem, san-test-all-types.der\n" |
| 325 | + |
| 326 | +# ============================================================================= |
| 327 | +# Cleanup and summary |
| 328 | +# ============================================================================= |
| 329 | +printf "\n[7/7] Cleanup and verification...\n" |
| 330 | + |
| 331 | +# Remove CA serial file |
| 332 | +rm -f "$SAN_DIR/san-test-ca-cert.srl" |
| 333 | + |
| 334 | +# Remove all private keys except CA (tests only need certs) |
| 335 | +# Uncomment if you want to keep keys minimal: |
| 336 | +# rm -f "$SAN_DIR/san-test-dns-ip-key.pem" |
| 337 | +# rm -f "$SAN_DIR/san-test-email-uri-key.pem" |
| 338 | +# rm -f "$SAN_DIR/san-test-othername-upn-key.pem" |
| 339 | +# rm -f "$SAN_DIR/san-test-dirname-rid-key.pem" |
| 340 | +# rm -f "$SAN_DIR/san-test-all-types-key.pem" |
| 341 | + |
| 342 | +printf "\n========================================\n" |
| 343 | +printf "SAN Test Certificate Generation Complete\n" |
| 344 | +printf "========================================\n" |
| 345 | +printf "\nGenerated files in %s/:\n" "$SAN_DIR" |
| 346 | +ls -la "$SAN_DIR"/*.pem "$SAN_DIR"/*.der 2>/dev/null | awk '{print " " $NF}' |
| 347 | + |
| 348 | +printf "\nVerifying SAN extensions in generated certificates:\n" |
| 349 | + |
| 350 | +printf "\n--- san-test-dns-ip.pem ---\n" |
| 351 | +openssl x509 -in "$SAN_DIR/san-test-dns-ip.pem" -noout -text | grep -A20 "Subject Alternative Name" | head -10 |
| 352 | + |
| 353 | +printf "\n--- san-test-email-uri.pem ---\n" |
| 354 | +openssl x509 -in "$SAN_DIR/san-test-email-uri.pem" -noout -text | grep -A20 "Subject Alternative Name" | head -10 |
| 355 | + |
| 356 | +printf "\n--- san-test-othername-upn.pem ---\n" |
| 357 | +openssl x509 -in "$SAN_DIR/san-test-othername-upn.pem" -noout -text | grep -A20 "Subject Alternative Name" | head -10 |
| 358 | + |
| 359 | +printf "\n--- san-test-dirname-rid.pem ---\n" |
| 360 | +openssl x509 -in "$SAN_DIR/san-test-dirname-rid.pem" -noout -text | grep -A20 "Subject Alternative Name" | head -15 |
| 361 | + |
| 362 | +printf "\n--- san-test-all-types.pem (comprehensive) ---\n" |
| 363 | +openssl x509 -in "$SAN_DIR/san-test-all-types.pem" -noout -text | grep -A50 "Subject Alternative Name" | head -30 |
| 364 | + |
| 365 | +printf "\nDone! Certificates are ready for testing WolfSSLAltName functionality.\n" |
| 366 | + |
0 commit comments