|
| 1 | +# OCPP 1.6 Security Profiles Configuration Guide |
| 2 | + |
| 3 | +This document describes how to configure SteVe to support the three OCPP 1.6 security profiles defined in the OCPP 1.6 Security Whitepaper Edition 3. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Security Profile Overview |
| 8 | + |
| 9 | +### Profile 0: Unsecured Transport with Basic Authentication |
| 10 | +- **Transport**: HTTP or WebSocket (ws://) |
| 11 | +- **Authentication**: HTTP Basic Authentication |
| 12 | +- **Encryption**: None |
| 13 | +- **Use Case**: Development, testing, closed networks |
| 14 | + |
| 15 | +### Profile 1: Unsecured Transport with Basic Authentication |
| 16 | +- **Transport**: HTTP or WebSocket (ws://) |
| 17 | +- **Authentication**: HTTP Basic Authentication + Charge Point Password |
| 18 | +- **Encryption**: None |
| 19 | +- **Use Case**: Private networks with additional authentication layer |
| 20 | + |
| 21 | +### Profile 2: TLS with Basic Authentication |
| 22 | +- **Transport**: HTTPS or Secure WebSocket (wss://) |
| 23 | +- **Authentication**: HTTP Basic Authentication + TLS Server Certificate |
| 24 | +- **Encryption**: TLS 1.2 or higher |
| 25 | +- **Use Case**: Production environments with server authentication |
| 26 | + |
| 27 | +### Profile 3: TLS with Client-Side Certificates |
| 28 | +- **Transport**: HTTPS or Secure WebSocket (wss://) |
| 29 | +- **Authentication**: Mutual TLS (mTLS) with client certificates |
| 30 | +- **Encryption**: TLS 1.2 or higher |
| 31 | +- **Use Case**: High-security production environments |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Configuration Properties |
| 36 | + |
| 37 | +Add these properties to `application-prod.properties` or `application-test.properties`: |
| 38 | + |
| 39 | +```properties |
| 40 | +# OCPP Security Profile (0, 1, 2, or 3) |
| 41 | +ocpp.security.profile=2 |
| 42 | + |
| 43 | +# TLS Configuration (required for Profile 2 and 3) |
| 44 | +ocpp.security.tls.enabled=true |
| 45 | + |
| 46 | +# Server Keystore (contains server certificate and private key) |
| 47 | +ocpp.security.tls.keystore.path=/path/to/server-keystore.jks |
| 48 | +ocpp.security.tls.keystore.password=your-keystore-password |
| 49 | +ocpp.security.tls.keystore.type=JKS |
| 50 | + |
| 51 | +# Truststore (contains trusted CA certificates) |
| 52 | +ocpp.security.tls.truststore.path=/path/to/truststore.jks |
| 53 | +ocpp.security.tls.truststore.password=your-truststore-password |
| 54 | +ocpp.security.tls.truststore.type=JKS |
| 55 | + |
| 56 | +# Client Certificate Authentication (required for Profile 3) |
| 57 | +ocpp.security.tls.client.auth=false |
| 58 | + |
| 59 | +# TLS Protocol Versions (comma-separated) |
| 60 | +ocpp.security.tls.protocols=TLSv1.2,TLSv1.3 |
| 61 | + |
| 62 | +# TLS Cipher Suites (optional, leave empty for defaults) |
| 63 | +ocpp.security.tls.ciphers= |
| 64 | +``` |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## Profile 0 Configuration (Unsecured) |
| 69 | + |
| 70 | +**⚠️ NOT RECOMMENDED FOR PRODUCTION** |
| 71 | + |
| 72 | +```properties |
| 73 | +ocpp.security.profile=0 |
| 74 | +ocpp.security.tls.enabled=false |
| 75 | + |
| 76 | +# Use HTTP Basic Auth credentials |
| 77 | +auth.user=admin |
| 78 | +auth.password=your-password |
| 79 | +``` |
| 80 | + |
| 81 | +**WebSocket URL**: `ws://your-server:8080/steve/websocket/CentralSystemService/{chargePointId}` |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## Profile 1 Configuration (Basic Auth Only) |
| 86 | + |
| 87 | +**⚠️ NOT RECOMMENDED FOR PRODUCTION** |
| 88 | + |
| 89 | +```properties |
| 90 | +ocpp.security.profile=1 |
| 91 | +ocpp.security.tls.enabled=false |
| 92 | + |
| 93 | +# Configure charge point authorization keys in database |
| 94 | +# Each charge point should have an authorization_key set |
| 95 | +``` |
| 96 | + |
| 97 | +**WebSocket URL**: `ws://your-server:8080/steve/websocket/CentralSystemService/{chargePointId}` |
| 98 | + |
| 99 | +**Database**: Set `authorization_key` column in `charge_box` table for each charge point. |
| 100 | + |
| 101 | +--- |
| 102 | + |
| 103 | +## Profile 2 Configuration (TLS + Basic Auth) |
| 104 | + |
| 105 | +**✅ RECOMMENDED FOR PRODUCTION** |
| 106 | + |
| 107 | +### Step 1: Generate Server Certificate |
| 108 | + |
| 109 | +```bash |
| 110 | +# Create server keystore with self-signed certificate (for testing) |
| 111 | +keytool -genkeypair -alias steve-server \ |
| 112 | + -keyalg RSA -keysize 2048 -validity 365 \ |
| 113 | + -keystore server-keystore.jks \ |
| 114 | + -storepass changeit \ |
| 115 | + -dname "CN=steve.example.com, OU=SteVe, O=Example, L=City, ST=State, C=US" |
| 116 | + |
| 117 | +# OR: Import existing certificate and private key |
| 118 | +# (Use openssl to convert PEM to PKCS12, then import to JKS) |
| 119 | +``` |
| 120 | + |
| 121 | +### Step 2: Configure Properties |
| 122 | + |
| 123 | +```properties |
| 124 | +ocpp.security.profile=2 |
| 125 | +ocpp.security.tls.enabled=true |
| 126 | + |
| 127 | +# Server certificate |
| 128 | +ocpp.security.tls.keystore.path=/opt/steve/certs/server-keystore.jks |
| 129 | +ocpp.security.tls.keystore.password=changeit |
| 130 | +ocpp.security.tls.keystore.type=JKS |
| 131 | + |
| 132 | +# Enable HTTPS on Jetty |
| 133 | +https.enabled=true |
| 134 | +https.port=8443 |
| 135 | +keystore.path=/opt/steve/certs/server-keystore.jks |
| 136 | +keystore.password=changeit |
| 137 | + |
| 138 | +# Client authentication NOT required for Profile 2 |
| 139 | +ocpp.security.tls.client.auth=false |
| 140 | +``` |
| 141 | + |
| 142 | +### Step 3: Configure Charge Points |
| 143 | + |
| 144 | +**WebSocket URL**: `wss://steve.example.com:8443/steve/websocket/CentralSystemService/{chargePointId}` |
| 145 | + |
| 146 | +**Certificate**: Charge points must trust the server certificate. Install the CA certificate or server certificate on charge points. |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +## Profile 3 Configuration (Mutual TLS) |
| 151 | + |
| 152 | +**✅ RECOMMENDED FOR HIGH-SECURITY ENVIRONMENTS** |
| 153 | + |
| 154 | +### Step 1: Generate CA Certificate |
| 155 | + |
| 156 | +```bash |
| 157 | +# Create CA private key and certificate |
| 158 | +openssl genrsa -out ca-key.pem 4096 |
| 159 | +openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem \ |
| 160 | + -subj "/CN=SteVe CA/O=Example/C=US" |
| 161 | +``` |
| 162 | + |
| 163 | +### Step 2: Generate Server Certificate (Signed by CA) |
| 164 | + |
| 165 | +```bash |
| 166 | +# Generate server private key and CSR |
| 167 | +openssl genrsa -out server-key.pem 2048 |
| 168 | +openssl req -new -key server-key.pem -out server.csr \ |
| 169 | + -subj "/CN=steve.example.com/O=Example/C=US" |
| 170 | + |
| 171 | +# Sign server certificate with CA |
| 172 | +openssl x509 -req -in server.csr -CA ca-cert.pem -CAkey ca-key.pem \ |
| 173 | + -CAcreateserial -out server-cert.pem -days 365 |
| 174 | + |
| 175 | +# Convert to PKCS12 |
| 176 | +openssl pkcs12 -export -in server-cert.pem -inkey server-key.pem \ |
| 177 | + -out server.p12 -name steve-server -passout pass:changeit |
| 178 | + |
| 179 | +# Import to JKS keystore |
| 180 | +keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 \ |
| 181 | + -destkeystore server-keystore.jks -deststoretype JKS \ |
| 182 | + -srcstorepass changeit -deststorepass changeit |
| 183 | +``` |
| 184 | + |
| 185 | +### Step 3: Create Truststore with CA Certificate |
| 186 | + |
| 187 | +```bash |
| 188 | +# Import CA certificate to truststore |
| 189 | +keytool -import -trustcacerts -alias ca-cert \ |
| 190 | + -file ca-cert.pem -keystore truststore.jks \ |
| 191 | + -storepass changeit -noprompt |
| 192 | +``` |
| 193 | + |
| 194 | +### Step 4: Generate Client Certificates (for each Charge Point) |
| 195 | + |
| 196 | +```bash |
| 197 | +# Generate client private key and CSR |
| 198 | +openssl genrsa -out client-cp001-key.pem 2048 |
| 199 | +openssl req -new -key client-cp001-key.pem -out client-cp001.csr \ |
| 200 | + -subj "/CN=CP001/O=Example/C=US" |
| 201 | + |
| 202 | +# Sign client certificate with CA |
| 203 | +openssl x509 -req -in client-cp001.csr -CA ca-cert.pem -CAkey ca-key.pem \ |
| 204 | + -CAcreateserial -out client-cp001-cert.pem -days 365 |
| 205 | + |
| 206 | +# Convert to PKCS12 for charge point |
| 207 | +openssl pkcs12 -export -in client-cp001-cert.pem -inkey client-cp001-key.pem \ |
| 208 | + -out client-cp001.p12 -name cp001 -passout pass:changeit |
| 209 | +``` |
| 210 | + |
| 211 | +### Step 5: Configure Properties |
| 212 | + |
| 213 | +```properties |
| 214 | +ocpp.security.profile=3 |
| 215 | +ocpp.security.tls.enabled=true |
| 216 | + |
| 217 | +# Server certificate |
| 218 | +ocpp.security.tls.keystore.path=/opt/steve/certs/server-keystore.jks |
| 219 | +ocpp.security.tls.keystore.password=changeit |
| 220 | +ocpp.security.tls.keystore.type=JKS |
| 221 | + |
| 222 | +# Truststore with CA certificate (to verify client certificates) |
| 223 | +ocpp.security.tls.truststore.path=/opt/steve/certs/truststore.jks |
| 224 | +ocpp.security.tls.truststore.password=changeit |
| 225 | +ocpp.security.tls.truststore.type=JKS |
| 226 | + |
| 227 | +# Require client certificates |
| 228 | +ocpp.security.tls.client.auth=true |
| 229 | + |
| 230 | +# TLS protocols |
| 231 | +ocpp.security.tls.protocols=TLSv1.2,TLSv1.3 |
| 232 | + |
| 233 | +# Enable HTTPS |
| 234 | +https.enabled=true |
| 235 | +https.port=8443 |
| 236 | +keystore.path=/opt/steve/certs/server-keystore.jks |
| 237 | +keystore.password=changeit |
| 238 | +``` |
| 239 | + |
| 240 | +### Step 6: Install Client Certificates on Charge Points |
| 241 | + |
| 242 | +1. Transfer `client-cp001.p12` to charge point CP001 |
| 243 | +2. Configure charge point to use client certificate for mTLS |
| 244 | +3. Configure charge point with CA certificate to verify server |
| 245 | +4. Set WebSocket URL: `wss://steve.example.com:8443/steve/websocket/CentralSystemService/CP001` |
| 246 | + |
| 247 | +--- |
| 248 | + |
| 249 | +## Security Best Practices |
| 250 | + |
| 251 | +### Certificate Management |
| 252 | + |
| 253 | +1. **Use a proper CA**: For production, use certificates from a trusted CA (Let's Encrypt, DigiCert, etc.) |
| 254 | +2. **Certificate rotation**: Renew certificates before expiry |
| 255 | +3. **Revocation**: Implement CRL or OCSP for certificate revocation |
| 256 | +4. **Key length**: Use at least 2048-bit RSA keys or 256-bit ECC keys |
| 257 | +5. **Storage**: Protect private keys with strong passwords and secure storage |
| 258 | + |
| 259 | +### TLS Configuration |
| 260 | + |
| 261 | +1. **Protocol versions**: Use TLS 1.2 or higher, disable SSLv3 and TLS 1.0/1.1 |
| 262 | +2. **Cipher suites**: Use strong ciphers (AES-GCM, ChaCha20-Poly1305) |
| 263 | +3. **Perfect Forward Secrecy**: Prefer ECDHE or DHE cipher suites |
| 264 | +4. **HSTS**: Enable HTTP Strict Transport Security |
| 265 | + |
| 266 | +### Recommended Cipher Suites |
| 267 | + |
| 268 | +```properties |
| 269 | +ocpp.security.tls.ciphers=\ |
| 270 | + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\ |
| 271 | + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\ |
| 272 | + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,\ |
| 273 | + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,\ |
| 274 | + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 |
| 275 | +``` |
| 276 | + |
| 277 | +--- |
| 278 | + |
| 279 | +## Database Configuration |
| 280 | + |
| 281 | +The `charge_box` table includes security-related columns: |
| 282 | + |
| 283 | +```sql |
| 284 | +-- Security profile for this charge point (0-3) |
| 285 | +ALTER TABLE charge_box ADD COLUMN security_profile INT DEFAULT 0; |
| 286 | + |
| 287 | +-- Authorization key for Profile 1+ (optional) |
| 288 | +ALTER TABLE charge_box ADD COLUMN authorization_key VARCHAR(100); |
| 289 | + |
| 290 | +-- CPO name (for certificate validation) |
| 291 | +ALTER TABLE charge_box ADD COLUMN cpo_name VARCHAR(255); |
| 292 | + |
| 293 | +-- Certificate store max length |
| 294 | +ALTER TABLE charge_box ADD COLUMN certificate_store_max_length INT; |
| 295 | + |
| 296 | +-- Additional root certificate check |
| 297 | +ALTER TABLE charge_box ADD COLUMN additional_root_certificate_check BOOLEAN DEFAULT FALSE; |
| 298 | +``` |
| 299 | + |
| 300 | +--- |
| 301 | + |
| 302 | +## Troubleshooting |
| 303 | + |
| 304 | +### Connection Fails with "SSL Handshake Error" |
| 305 | + |
| 306 | +- **Check**: Certificate validity (not expired) |
| 307 | +- **Check**: Hostname matches CN in server certificate |
| 308 | +- **Check**: Charge point trusts the server certificate or CA |
| 309 | + |
| 310 | +### Client Certificate Not Accepted |
| 311 | + |
| 312 | +- **Check**: Client certificate signed by trusted CA in truststore |
| 313 | +- **Check**: Client certificate not expired |
| 314 | +- **Check**: `ocpp.security.tls.client.auth=true` is set |
| 315 | + |
| 316 | +### TLS Version Mismatch |
| 317 | + |
| 318 | +- **Check**: Both server and charge point support same TLS version |
| 319 | +- **Check**: `ocpp.security.tls.protocols` includes supported versions |
| 320 | + |
| 321 | +### Certificate Validation Fails |
| 322 | + |
| 323 | +- **Check**: CN in certificate matches charge point ID or hostname |
| 324 | +- **Check**: Certificate chain is complete |
| 325 | +- **Check**: CA certificate imported to truststore |
| 326 | + |
| 327 | +--- |
| 328 | + |
| 329 | +## Testing TLS Configuration |
| 330 | + |
| 331 | +### Test Server Certificate with OpenSSL |
| 332 | + |
| 333 | +```bash |
| 334 | +# Test TLS connection |
| 335 | +openssl s_client -connect steve.example.com:8443 -showcerts |
| 336 | + |
| 337 | +# Test with client certificate |
| 338 | +openssl s_client -connect steve.example.com:8443 \ |
| 339 | + -cert client-cp001-cert.pem -key client-cp001-key.pem |
| 340 | +``` |
| 341 | + |
| 342 | +### Test WebSocket Connection |
| 343 | + |
| 344 | +```bash |
| 345 | +# Install wscat: npm install -g wscat |
| 346 | + |
| 347 | +# Test Profile 2 (wss://) |
| 348 | +wscat -c "wss://steve.example.com:8443/steve/websocket/CentralSystemService/CP001" |
| 349 | + |
| 350 | +# Test Profile 3 (wss:// with client cert) |
| 351 | +wscat -c "wss://steve.example.com:8443/steve/websocket/CentralSystemService/CP001" \ |
| 352 | + --cert client-cp001.p12 --passphrase changeit |
| 353 | +``` |
| 354 | + |
| 355 | +--- |
| 356 | + |
| 357 | +## References |
| 358 | + |
| 359 | +- [OCPP 1.6 Security Whitepaper Edition 3](https://openchargealliance.org/protocols/open-charge-point-protocol/) |
| 360 | +- [Java Keytool Documentation](https://docs.oracle.com/en/java/javase/17/docs/specs/man/keytool.html) |
| 361 | +- [OpenSSL Documentation](https://www.openssl.org/docs/) |
| 362 | +- [Spring Boot SSL Configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server) |
| 363 | + |
| 364 | +--- |
| 365 | + |
| 366 | +## Support |
| 367 | + |
| 368 | +For questions or issues: |
| 369 | +- GitHub: https://github.com/steve-community/steve/issues |
| 370 | +- OCPP Forum: https://openchargealliance.org/ |
| 371 | + |
| 372 | +--- |
| 373 | + |
| 374 | +**Last Updated**: 2025-09-27 |
| 375 | +**SteVe Version**: 3.x with OCPP 1.6 Security Extensions |
0 commit comments