<!--
{
  "documentType" : "article",
  "framework" : "OpenSSL",
  "identifier" : "/documentation/OpenSSL/SecurityConsiderations",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Security Considerations"
}
-->

# Security Considerations

Production-readiness caveats, MVP gaps, disabled algorithms, and runtime auditing guidance for `swift-openssl`. This article is the single source of truth for whether to depend on this package in a given threat model.

## Overview

> Warning: **Cryptographic test vectors have not been integrated into the test suite**, and this package is pre-1.0. Do not use it in production until proper verification is in place. The sections below describe the specific gaps that motivate that caution and the compensating controls available today.

### Pre-1.0 API Stability

The package is pre-1.0 and uses [SemVer major version zero](https://semver.org/#spec-item-4), which reserves `0.y.z` as *“anything may change at any time.”* The public API may change with any `0.y.z` release. Pin a version using `exact:` to avoid unexpected breaking changes.

Practical consequences:

- Do **not** use `from:` or `upToNextMinor:` requirements in `Package.swift`. Pin `exact: "0.x.y"` until the package reaches 1.0.
- Inspect each upgrade. The observable behavior of ``doc://OpenSSL/documentation/OpenSSL/OpenSSLError`` (including its associated `String` reasons) is part of the API contract for tests that pattern-match on it.
- When an upgrade changes a citation, a test vector, or the set of ``doc://OpenSSL/documentation/OpenSSL/OpenSSLError`` cases produced on a code path, bump your own pin deliberately.

### MVP Scope and Missing Capabilities

Shipping today:

- ``doc://OpenSSL/documentation/OpenSSL/SHA256/hash(data:)`` and ``doc://OpenSSL/documentation/OpenSSL/SHA256/hash(string:)`` — functional, test-vector-matching against FIPS 180-4 canonical values.
- ``doc://OpenSSL/documentation/OpenSSL/Base64URL/encode(_:)`` and ``doc://OpenSSL/documentation/OpenSSL/Base64URL/decode(_:)`` — functional, RFC 4648 §5 compliant.
- ``doc://OpenSSL/documentation/OpenSSL/RSA/PrivateKey/init(pemRepresentation:)`` and ``doc://OpenSSL/documentation/OpenSSL/RSA/PublicKey/init(pemRepresentation:)`` — PEM frame validation only, no DER structural checks.
- ``doc://OpenSSL/documentation/OpenSSL/SSL/versionString`` — functional, reports the runtime-linked `libcrypto` version.

Not shipping today (future work):

- **RSA signing and verification**. Requires the OpenSSL provider layer (`OSSL_PROVIDER_load`, `EVP_PKEY_sign_init`, `EVP_PKEY_verify_init`), which is not integrated. Key parsing via ``doc://OpenSSL/documentation/OpenSSL/RSA/PrivateKey/init(pemRepresentation:)`` and ``doc://OpenSSL/documentation/OpenSSL/RSA/PublicKey/init(pemRepresentation:)`` is functional and unaffected.
- **TLS client or server context setup**. The `SSL` namespace exposes only ``doc://OpenSSL/documentation/OpenSSL/SSL/versionString``. No session API, no context builder, no ALPN helpers.
- **X.509 certificate chain validation**.
- **HMAC, HKDF, AEAD, Ed25519, X25519, ECDH, ECDSA** Swift wrappers. `libcrypto` ships the C surface for these; no Swift API layer exists yet.
- **Key generation** for any algorithm family.
- **Algorithm-level test-vector validation** (see next section).

For algorithms Apple’s frameworks already cover well — SHA-2, AES-GCM, ChaCha20-Poly1305, HKDF, Curve25519 — prefer [`swift-crypto`](https://github.com/apple/swift-crypto) or CryptoKit until this package grows the corresponding idiomatic surface.

### Cryptographic Test Vectors

The core constraint stated in the overview: **cryptographic test vectors have not been integrated into the test suite.** This package’s CI runs a small set of hand-picked digest and base64 vectors and negative tests on malformed PEM input; it does **not** run against [Project Wycheproof](https://github.com/google/wycheproof) or [NIST CAVP](https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program) vector sets.

What this means for callers:

- SHA-256 output is independently verifiable against the short vectors in [RFC 6234 §8.5](https://datatracker.ietf.org/doc/html/rfc6234#section-8.5) and the FIPS 180-4 §A.1 empty-input digest. These are the test vectors this project relies on today.
- Any algorithm not already shipping behind a Swift API in `OpenSSL` is untested at the vector level *from this project*. The underlying `libcrypto` C code is upstream OpenSSL 3.6.2 — its own CI covers CAVP — but the Swift wrappers that will sit on top of it are not yet written, let alone validated.
- Project constitution Principle II requires published-vector validation (Wycheproof, NIST CAVP, RFC vectors) for every algorithm family before it is marked “tested.” Phase 2 of the roadmap backfills SHA-256 coverage and adds HMAC / HKDF / AEAD as those APIs land.

Production users needing FIPS 140-3 validation should not treat this package as fulfilling that requirement; the Swift layer is out-of-scope for any upstream FIPS module validation.

### Disabled Algorithms

Multiple algorithms are intentionally disabled via both `subtree.yaml` extraction excludes and `OPENSSL_NO_*` defines in the generated `configuration.h`. Attempting to use them — even via the raw `libcrypto` C bindings — will fail to link:

|Category          |Algorithms                                    |Rationale                                        |
|------------------|----------------------------------------------|-------------------------------------------------|
|Legacy ciphers    |RC5, RC2, IDEA, Blowfish, CAST, SEED, Camellia|Deprecated, rarely used                          |
|Legacy hashes     |MDC2, Whirlpool, MD2, MD4, Blake2             |Deprecated or specialized                        |
|Regional standards|SM2, SM3, SM4, ARIA, GOST                     |Chinese/Korean/Russian national standards        |
|Post-quantum      |LMS, ML-DSA, ML-KEM, SLH-DSA                  |Experimental; increases binary size significantly|
|Platform-specific |`ec-nistp-64-gcc-128`, `padlockeng`           |Require specific compiler or hardware            |

Re-enabling an algorithm requires updating both places (subtree excludes and the Configure flag set) and running the full extraction recipe documented in [`Vendor/AGENTS.md`](https://github.com/21-DOT-DEV/swift-openssl/blob/main/Vendor/AGENTS.md). Do not patch one without the other.

### Constant-Time Comparison

[`SHA256.SHA256Digest`](/documentation/OpenSSL/SHA256/SHA256Digest) conforms to `Equatable` via Foundation’s `Data` equality, which is **not** constant-time. Using `==` on two secret-derived digests leaks timing information proportional to the first differing byte.

Rules:

- Do not compare MAC tags, authenticator values, or any secret-derived digest with `==`.
- Use a constant-time comparison primitive from your HMAC or AEAD layer when available (CryptoKit’s `HashedAuthenticationCode` values compare constant-time internally via Apple’s implementation).
- When no such primitive is at hand, implement one: iterate byte-by-byte, accumulating `a[i] ^ b[i]` into an `UInt8` result, and check equality only on the aggregate. Never branch on intermediate results.

[`encode(_:)`](/documentation/OpenSSL/Base64URL/encode(_:)) and [`decode(_:)`](/documentation/OpenSSL/Base64URL/decode(_:)) are also not constant-time: their running time depends on both input length and content. Do not pass secret-dependent material through them on side-channel-sensitive paths.

### PEM Parsing Limitations

[`init(pemRepresentation:)`](/documentation/OpenSSL/RSA/PrivateKey/init(pemRepresentation:)) and [`init(pemRepresentation:)`](/documentation/OpenSSL/RSA/PublicKey/init(pemRepresentation:)) perform outer-frame validation only. Specifically:

- The input must be valid UTF-8.
- The input must contain both a `-----BEGIN` marker and the appropriate `PRIVATE KEY-----` or `PUBLIC KEY-----` marker.
- **The base64-encoded DER payload inside the PEM frame is not structurally validated.** A malformed SubjectPublicKeyInfo or PKCS#8 envelope will pass ingestion and surface as an error only once the provider layer lands and attempts to use the bytes.

Consumers that need structural validation today must decode and re-verify the DER themselves — typically by attempting a parse with a Swift ASN.1 library or by exporting to OpenSSL’s CLI via `openssl asn1parse -inform PEM -in key.pem`. The PEM frame grammar itself is defined by [RFC 7468](https://datatracker.ietf.org/doc/html/rfc7468).

### Runtime OpenSSL Version Auditing

Every binary that ships this package carries a specific OpenSSL version statically compiled into `libcrypto`. Use [`versionString`](/documentation/OpenSSL/SSL/versionString) to report it at runtime, then cross-reference against the [OpenSSL security advisories](https://www.openssl.org/news/vulnerabilities.html) before cutting a release build.

```swift
import OpenSSL
print(SSL.versionString)
// OpenSSL 3.6.2 ...
```

Guidance:

- Run this check in a release-gate CI step that fails if the reported version falls below your minimum acceptable patch level.
- Transitive consumers (a package that depends on `swift-tor`, which depends on `swift-openssl`) inherit the same linked runtime and the same CVE surface. Audit the whole graph, not just your direct dependency.
- The version is compile-time baked, not load-time dynamic. A binary shipped with OpenSSL 3.6.2 stays at 3.6.2 until rebuilt against a newer vendored source tree.

### Reporting Vulnerabilities

Security issues in this package are handled per [`SECURITY.md`](https://github.com/21-DOT-DEV/swift-openssl/blob/main/SECURITY.md) and the umbrella [21-DOT-DEV security policy](https://github.com/21-DOT-DEV/.github/blob/main/SECURITY.md). Do not open public GitHub issues for suspected vulnerabilities — follow the private disclosure process documented in those files.

Vulnerabilities in upstream OpenSSL itself should be reported directly to [the OpenSSL project](https://openssl-library.org/policies/general-supporting-policies/vulnerabilities/); this package will pick them up via a subtree update once fixed upstream.