Documentation
¶
Overview ¶
Package smx509 provides SM2-aware X.509 certificate handling, extending crypto/x509 with national cryptography support.
It automatically selects the standard library or gmsm/smx509 backend based on the key type, so callers do not need to distinguish SM2 from standard ECDSA.
Status: lower-level SM2-aware X.509 helper; for the recommended facade, use the cert package
This file adds RFC 6960 response-level extension support (notably the §4.4.1 nonce echo) to OCSP response construction, plus request/response nonce extraction helpers. The upstream implementations — x/crypto/ocsp and this package's CreateOCSPResponse/template path — only support singleResponse extensions, so a nonce cannot be echoed in its standard-mandated position. The DER assembly mirrors ocsp.CreateResponse / createSM2OCSPResponse; the responderID-by-Name, CertID hashing and basicResponse envelope are identical, with these differences:
- responseData carries responseExtensions ([1] EXPLICIT, RFC 6960 §4.2.1);
- revokedInfo omits cRLReason entirely when reason=unspecified(0) (RFC 5280 §5.3.1 SHOULD be absent);
- the CertID hash is caller-controlled (echo the request's HashAlgorithm);
- one signer dispatch covers SM2 (SM2+SM3 with ZA), RSA, ECDSA and Ed25519 — x/crypto.CreateResponse is not reused because it cannot emit responseExtensions.
Interop note: encoding/asn1 ignores trailing SEQUENCE elements it has no struct field for, so responses carrying responseExtensions parse fine with x/crypto's ParseResponse and with this package's SM2 parser (verified experimentally against x/crypto and `openssl ocsp -text`); the nonce is always encoded in the standard responseExtensions position.
Verification note: x/crypto's ParseResponse can only VERIFY responses signed with RSA or ECDSA (its algorithm table has no Ed25519 or SM2 entries). SM2-signed responses verify via this package's ParseOCSPResponseWithIssuer; Ed25519-signed responses must be verified by the caller (ed25519.Verify over the raw tbsResponseData) — see the ocsp_ext_test.go Ed25519 case for a reference implementation.
Index ¶
- Constants
- Variables
- func AddRFC5280KeyIdentifiers(template *x509.Certificate, subjectKeyID []byte, authorityKeyID []byte, ...) error
- func CheckCertificateRequestSignature(csr *x509.CertificateRequest) error
- func CreateAuthorityInfoAccessExtension(ocspURLs, caIssuerURLs []string) (pkix.Extension, error)
- func CreateAuthorityKeyIdentifierExtension(keyID []byte) (pkix.Extension, error)
- func CreateCRLDistributionPointsExtension(fullNames []string) (pkix.Extension, error)
- func CreateCRLReasonExtension(reason CRLReason) (pkix.Extension, error)
- func CreateCertificate(template, parent *x509.Certificate, pub, priv any) ([]byte, error)
- func CreateCertificateRequest(template *x509.CertificateRequest, priv any) ([]byte, error)
- func CreateInvalidityDateExtension(date time.Time) (pkix.Extension, error)
- func CreateOCSPResponse(issuer, responderCert *x509.Certificate, template *ocsp.Response, ...) ([]byte, error)
- func CreateOCSPResponseExt(issuer, responderCert *x509.Certificate, p *OCSPResponseParams, ...) ([]byte, error)
- func CreateRevocationList(template *x509.RevocationList, issuer *x509.Certificate, signer crypto.Signer) ([]byte, error)
- func CreateSubjectKeyIdentifierExtension(keyID []byte) (pkix.Extension, error)
- func DecryptPEMPrivateKey(pemData []byte, password string) ([]byte, error)
- func DecryptPEMPrivateKeyDER(pemData []byte, password string) ([]byte, error)
- func ExtractOCSPRequestNonce(reqBytes []byte) []byte
- func ExtractPublicKey(priv any) (crypto.PublicKey, error)
- func FingerprintHash(cert *x509.Certificate, h crypto.Hash) (string, error)
- func FingerprintSHA256(cert *x509.Certificate) string
- func GenerateAuthorityKeyIdentifier(issuerPubKey crypto.PublicKey) ([]byte, error)
- func GenerateSerialNumber() (*big.Int, error)
- func GenerateSubjectKeyIdentifier(pubKey crypto.PublicKey) ([]byte, error)
- func GetAuthorityInfoAccess(cert *x509.Certificate) (ocspURLs, caIssuerURLs []string)
- func GetAuthorityKeyIdentifier(cert *x509.Certificate) []byte
- func GetSubjectKeyIdentifier(cert *x509.Certificate) []byte
- func IsSM2Key(key any) bool
- func IsSM2PublicKey(pub any) bool
- func IsSM3CertID(resp *ocsp.Response) bool
- func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)
- func MarshalPKIXPublicKey(pub any) ([]byte, error)
- func MarshalPrivateKey(key any) ([]byte, error)
- func NewOCSPResponseTemplate(cert, issuer *x509.Certificate, status int, thisUpdate, nextUpdate time.Time) (*ocsp.Response, error)
- func OCSPErrorResponse(status int) []byte
- func PEMTypeForPrivateKey(key any) string
- func ParseCertificate(der []byte) (*x509.Certificate, error)
- func ParseCertificatePEM(pemData []byte) (*x509.Certificate, error)
- func ParseCertificateRequest(der []byte) (*x509.CertificateRequest, error)
- func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error)
- func ParseInvalidityDate(extensions []pkix.Extension) (time.Time, bool)
- func ParseOCSPRequest(data []byte) (*ocsp.Request, error)
- func ParseOCSPResponse(data []byte) (*ocsp.Response, error)deprecated
- func ParseOCSPResponseUnverified(data []byte) (*ocsp.Response, error)
- func ParseOCSPResponseWithIssuer(data []byte, issuer *x509.Certificate) (*ocsp.Response, error)
- func ParseOCSPResponseWithIssuerAt(data []byte, issuer *x509.Certificate, now time.Time) (*ocsp.Response, error)
- func ParsePKCS8PrivateKey(der []byte) (any, error)
- func ParsePKIXPublicKey(der []byte) (any, error)
- func ParsePrivateKeyPEM(pemData []byte) (any, error)
- func PublicKeyAlgorithmForPrivateKey(key any) x509.PublicKeyAlgorithm
- func ResponseNonce(respDER []byte) ([]byte, error)
- func SignatureAlgorithmForPrivateKey(key any) x509.SignatureAlgorithm
- func ToSMX509Certificate(cert *x509.Certificate) (*smx509.Certificate, error)
- func ToSMX509Certificates(certs []*x509.Certificate) ([]*smx509.Certificate, error)
- func ToStdCertificate(smCert *smx509.Certificate) (*x509.Certificate, error)
- func ToStdCertificates(certs []*smx509.Certificate) ([]*x509.Certificate, error)
- func ValidateKeyIdentifiers(cert *x509.Certificate) (bool, []string)
- func Verify(cert *x509.Certificate, opts VerifyOptions) error
- func VerifyDualCerts(signCert, encCert *x509.Certificate) error
- func VerifyOCSPResponseNonce(respDER, sentNonce []byte) error
- type CRLReason
- type CertPool
- type OCSPResponseParams
- type VerifyOptions
Constants ¶
OCSP status codes, mirroring golang.org/x/crypto/ocsp constants.
Variables ¶
var ( OIDAuthorityInfoAccess = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1} OIDAIAOCSP = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} OIDAIACAIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} )
RFC 5280 §4.2.2.1 Authority Information Access OIDs.
var ( OIDCRLReason = asn1.ObjectIdentifier{2, 5, 29, 21} OIDInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24} )
CRL extension OIDs (RFC 5280 §5.3).
var ( OIDSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14} OIDAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35} )
RFC 5280 certificate extension OIDs for key identifiers.
var CopyFieldDriftHook func(skipped []string)
CopyFieldDriftHook is an optional, dependency-free diagnostic hook invoked whenever a copyCertFields-based conversion silently skips one or more fields (field absent on the destination side, enum value outside the shared range, or incompatible types). It exists so tests and debugging tooling can observe struct drift between crypto/x509 and the gmsm/smx509 fork; production code leaves it nil (a no-op). The hook must not panic and must not retain the slice. Skips do NOT fail the conversion — they are surfaced only.
var ErrSerialZero = errors.New("smx509: generated serial number is zero")
ErrSerialZero is returned when the generated serial number happens to be zero, which RFC 5280 §4.1.2.2 forbids (serial must be a positive integer).
var OIDCRLDistributionPoints = asn1.ObjectIdentifier{2, 5, 29, 31}
CRLDistributionPoints OID (RFC 5280 §4.2.1.13).
Functions ¶
func AddRFC5280KeyIdentifiers ¶ added in v0.1.4
func AddRFC5280KeyIdentifiers( template *x509.Certificate, subjectKeyID []byte, authorityKeyID []byte, issuerPubKey crypto.PublicKey, ) error
AddRFC5280KeyIdentifiers attaches SKI and AKI extensions to a certificate template's ExtraExtensions. If subjectKeyID/authorityKeyID are empty, they are auto-generated from template.PublicKey / issuerPubKey respectively.
func CheckCertificateRequestSignature ¶
func CheckCertificateRequestSignature(csr *x509.CertificateRequest) error
CheckCertificateRequestSignature verifies a CSR signature, handling SM2 automatically.
func CreateAuthorityInfoAccessExtension ¶ added in v0.1.4
CreateAuthorityInfoAccessExtension builds an Authority Information Access (AIA) extension (RFC 5280 §4.2.2.1) from OCSP responder URLs and CA Issuers URLs. The extension is non-critical. Returns a zero Extension if both lists are empty OR contain only empty strings — matching CreateCRLDistributionPointsExtension's behavior (which also returns a zero Extension when no non-empty URLs remain, after filtering empties).
Note: crypto/x509.Certificate has direct fields only for CA Issuers (IssuingCertificateURL) — there is NO stdlib field for the OCSP access method. Use this helper to inject a complete AIA extension (covering OCSP) via ExtraExtensions.
func CreateAuthorityKeyIdentifierExtension ¶ added in v0.1.4
CreateAuthorityKeyIdentifierExtension builds an AuthorityKeyIdentifier extension (RFC 5280 §4.2.1.1) from a key identifier. AKI is non-critical.
As with CreateSubjectKeyIdentifierExtension, an empty keyID returns a zero-value extension with a nil error ("nothing to add"); a marshal failure returns an error.
func CreateCRLDistributionPointsExtension ¶ added in v0.1.4
CreateCRLDistributionPointsExtension builds a CRL Distribution Points extension (RFC 5280 §4.2.1.13) from a list of CRL URLs (fullName GeneralNames, URI form). The extension is non-critical. Returns a zero Extension if fullNames is empty.
In most cases callers can simply set template.CRLDistributionPoints and let crypto/x509 encode it; this helper is for cases where the extension must be injected directly into ExtraExtensions.
func CreateCRLReasonExtension ¶ added in v0.1.4
CreateCRLReasonExtension builds a CRLReason extension (RFC 5280 §5.3.1). The extension is non-critical.
Returns an error (rather than a zero-value pkix.Extension) when reason is outside the RFC 5280 §5.3.1 valid range (0-10 excluding 7) or ASN.1 marshaling fails. This makes an out-of-range reason an explicit, checkable failure instead of a sentinel the caller must remember to test for — preventing a malformed (empty-Value) extension from being silently injected into a CRL.
func CreateCertificate ¶
func CreateCertificate(template, parent *x509.Certificate, pub, priv any) ([]byte, error)
CreateCertificate creates a certificate, automatically selecting crypto/x509 or gmsm/smx509 based on the signer's key type.
func CreateCertificateRequest ¶
func CreateCertificateRequest(template *x509.CertificateRequest, priv any) ([]byte, error)
CreateCertificateRequest creates a CSR, automatically selecting crypto/x509 or gmsm/smx509 based on the key type.
func CreateInvalidityDateExtension ¶ added in v0.1.4
CreateInvalidityDateExtension builds an InvalidityDate extension (RFC 5280 §5.3.2) encoding the date the certificate is considered invalid. The extension is non-critical.
Returns an error on ASN.1 marshaling failure (effectively unreachable for a valid time.Time), making the failure explicit rather than a sentinel zero-value extension the caller must remember to skip.
func CreateOCSPResponse ¶
func CreateOCSPResponse(issuer, responderCert *x509.Certificate, template *ocsp.Response, signer crypto.Signer) ([]byte, error)
CreateOCSPResponse creates an OCSP response signed by the responder. If signer is an SM2 private key, the response is signed with SM2+SM3 (GM/T 0009-2012) via createSM2OCSPResponse; otherwise it delegates to golang.org/x/crypto/ocsp.CreateResponse, which cannot handle SM2 keys (its signingParamsForPublicKey rejects sm2.P256()).
issuer is the CA whose key issued the certificate being responded about (used to compute the CertID name/key hashes). responderCert is the certificate whose private key signs the response; it MAY equal issuer (CA-direct responder) or be a delegated responder cert signed by issuer.
func CreateOCSPResponseExt ¶ added in v0.5.0
func CreateOCSPResponseExt(issuer, responderCert *x509.Certificate, p *OCSPResponseParams, signer crypto.Signer) ([]byte, error)
CreateOCSPResponseExt builds a DER-encoded OCSP response with responseExtensions support. The signer dispatch covers SM2 (SM2+SM3 with ZA, default UID) and standard algorithms (RSA PKCS#1 v1.5, ECDSA, Ed25519; digest SHA-256 or stronger). It complements CreateOCSPResponse, which remains for the nonce-free ocsp.Response template path.
func CreateRevocationList ¶
func CreateRevocationList(template *x509.RevocationList, issuer *x509.Certificate, signer crypto.Signer) ([]byte, error)
CreateRevocationList creates a CRL signed by the issuer. If the issuer key is SM2, gmsm/smx509 is used for SM2+SM3 signing. template, issuer, and signer MUST all be non-nil.
func CreateSubjectKeyIdentifierExtension ¶ added in v0.1.4
CreateSubjectKeyIdentifierExtension builds a SubjectKeyIdentifier extension (RFC 5280 §4.2.1.2) from a key identifier. SKI is non-critical.
An empty keyID returns a zero-value pkix.Extension (Id == nil) with a nil error, signalling "no extension to add" — callers should check `ext.Id != nil` before appending. An ASN.1 marshal failure (effectively unreachable for a []byte) returns an error. This matches the (Extension, error) shape of the other Create*Extension helpers, keeping the four functions consistent.
func DecryptPEMPrivateKey ¶
DecryptPEMPrivateKey decrypts an encrypted PEM private key using the given password. Returns the decrypted key in PEM format. Supports PKCS#8 encrypted keys (PBES2/PBKDF2 with AES-CBC/GCM, SM4-CBC/GCM, SM3 PRF) and traditional PEM encryption (Proc-Type/DEK-Info headers with DES-CBC, DES-EDE3-CBC, AES-CBC). Traditional PEM encryption is accepted only for reading legacy OpenSSL-compatible keys; new encrypted keys should use PKCS#8 PBES2 with an authenticated or modern block cipher mode.
func DecryptPEMPrivateKeyDER ¶
DecryptPEMPrivateKeyDER decrypts an encrypted PEM private key and returns raw DER bytes.
func ExtractOCSPRequestNonce ¶ added in v0.5.0
ExtractOCSPRequestNonce parses the requestExtensions of a DER-encoded OCSP request and returns the id-pkix-OCSP-noarch nonce (nil when absent or the request is malformed — callers rejecting bad requests separately anyway). x/crypto's public ocsp.Request does not expose requestExtensions, hence this standalone helper.
func ExtractPublicKey ¶
ExtractPublicKey extracts the public key from a private key.
func FingerprintHash ¶ added in v0.1.4
FingerprintHash returns the hex-encoded fingerprint using the given hash (must be available, e.g. crypto.SHA1 for legacy OCSP CertID-style hashing).
Returns ("", nil) for a nil cert OR a cert with empty Raw. Returns an error if the hash is not linked into the binary.
Note: hash.Write's return values are intentionally ignored — the standard library's hash.Hash contract documents that Write never returns a non-nil error (hashes never fail to absorb input). This matches the convention in crypto/x509's own fingerprint helpers. The (n, err) tuple is part of the io.Writer signature hash.Hash embeds for stream-composability, not an indicator of per-Write failure.
func FingerprintSHA256 ¶ added in v0.1.4
func FingerprintSHA256(cert *x509.Certificate) string
FingerprintSHA256 returns the lowercase hex-encoded SHA-256 fingerprint of the certificate's DER encoding (cert.Raw). This is the canonical colon-free fingerprint form used by PKI discovery APIs, OCSP/CRT sharding, and pinning workflows.
Returns "" for a nil cert OR a cert with empty Raw (e.g. a freshly constructed *x509.Certificate{} that has never been parsed). A zero Raw would otherwise hash empty bytes and return a deterministic-but-meaningless value, masking the misconfiguration.
func GenerateAuthorityKeyIdentifier ¶ added in v0.1.4
GenerateAuthorityKeyIdentifier computes an AuthorityKeyIdentifier from an issuer public key using the SHA-1 method (consistent with SKI). SM2-aware: MarshalPKIXPublicKey handles both SM2 and standard keys.
func GenerateSerialNumber ¶ added in v0.1.4
GenerateSerialNumber returns a cryptographically random positive integer suitable for an X.509 certificate serial number (RFC 5280 §4.1.2.2).
The result is uniformly distributed in [1, 2^159), guaranteeing it fits in the 20-byte serial field without a DER leading sign byte while meeting the entropy recommendation for CA-issued certificates. Returns ErrSerialZero if the rare zero draw occurs (caller should retry).
func GenerateSubjectKeyIdentifier ¶ added in v0.1.4
GenerateSubjectKeyIdentifier computes a SubjectKeyIdentifier from a public key using the RFC 5280 §4.2.1.2 recommended method (SHA-1 over the PKIX-encoded public key). SHA-1 is safe for key-identifier binding (no preimage concern). SM2-aware: MarshalPKIXPublicKey handles both SM2 and standard keys.
func GetAuthorityInfoAccess ¶ added in v0.1.4
func GetAuthorityInfoAccess(cert *x509.Certificate) (ocspURLs, caIssuerURLs []string)
GetAuthorityInfoAccess extracts OCSP and CA Issuers URLs from a certificate's AIA extension.
Only URI-form GeneralNames (context-specific class 2, tag 6) are accepted; other GeneralName forms (IP, DNS, etc.) are skipped silently per the AIA common-practice expectation that accessLocation is a URI.
Return-value semantics — all three "no URLs" cases return (nil, nil) for caller-side simplicity (a nil slice tests false for "have an OCSP URL"). To distinguish the cause, inspect the inputs directly:
- cert == nil: caller passed nothing; the function is a no-op.
- cert non-nil but no AIA extension present: the cert simply does not carry AIA. Detect via cert.IsCA / a scan of cert.Extensions for OIDAuthorityInfoAccess before calling.
- AIA extension present but ASN.1 parse failed: malformed extension. This is rare and almost always indicates a corrupt or attacker-crafted certificate; the function logs nothing but returns nil so the caller degrades gracefully (treats the cert as having no AIA). If you need to detect this case programmatically, pre-scan cert.Extensions for the AIA OID and parse it yourself with a distinguishing error.
Non-URI accessLocation entries (Class != 2 or Tag != 6) are silently skipped rather than surfaced — RFC 5280 §4.2.2.1 restricts AIA to URI form, so a non-URI entry is malformed and skipping it matches common CA-browser practice.
func GetAuthorityKeyIdentifier ¶ added in v0.1.4
func GetAuthorityKeyIdentifier(cert *x509.Certificate) []byte
GetAuthorityKeyIdentifier extracts the AuthorityKeyIdentifier from a certificate. Prefers the pre-parsed cert.AuthorityKeyId; falls back to scanning Extensions and parsing the RFC 5280 SEQUENCE wrapper. Returns nil if absent or cert is nil.
func GetSubjectKeyIdentifier ¶ added in v0.1.4
func GetSubjectKeyIdentifier(cert *x509.Certificate) []byte
GetSubjectKeyIdentifier extracts the SubjectKeyIdentifier from a certificate. Prefers the pre-parsed cert.SubjectKeyId; falls back to scanning Extensions. Returns nil if absent or cert is nil.
func IsSM2Key ¶
IsSM2Key reports whether a private key is an SM2 key.
SM2 key identity convention (gmsm): an SM2 key IS an ECDSA key on the SM2 curve. gmsm registers sm2.P256() as a distinct curve object (not the stdlib's elliptic.P256()), and identification is by pointer equality against that registered object. Consequences:
- A *sm2.PrivateKey is SM2 by definition.
- A plain *ecdsa.PrivateKey whose Curve is the same sm2.P256() object is treated as SM2 (this is how SM2 keys surface after stdlib ASN.1 parsing).
- Changing gmsm's curve registration (e.g. returning a new P256() instance per call) would silently break this detection. If gmsm ever does so, identification must switch to parameter comparison.
func IsSM2PublicKey ¶
IsSM2PublicKey reports whether a public key is an SM2 public key.
Uses the same pointer-equality convention as IsSM2Key: the curve must be the exact gmsm-registered sm2.P256() object. See IsSM2Key for the full caveat.
func IsSM3CertID ¶ added in v0.5.0
IsSM3CertID reports whether the CertID of resp's first singleResponse uses the SM3 hash algorithm (GM/T 0009-2012, OID 1.2.156.10197.1.401).
Background: golang.org/x/crypto's ocsp.Response — the type returned by this package's OCSP parsers — cannot express SM3: its IssuerHash field is a crypto.Hash and crypto defines no SM3 constant. For an SM3-CertID response the SM2-aware parser therefore reports IssuerHash = crypto.SHA256. That is a forced misreporting, not the hash actually used in the CertID: recomputing issuer name/key hashes with resp.IssuerHash.New() would produce SHA-256 digests that never match the SM3 digests carried in the response. Use this predicate to branch, and hash with github.com/iuboy/pollux-go/sm3 instead.
The answer is derived from the raw DER in resp.Raw (the CertID hash OID is inspected directly, not the misreported IssuerHash), so it also works for responses parsed by x/crypto's own parser. A nil resp, an empty Raw, or a Raw that does not decode as a BasicOCSPResponse reports false.
func MarshalECPrivateKey ¶
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)
MarshalECPrivateKey serializes an EC (including SM2) private key to DER format.
func MarshalPKIXPublicKey ¶
MarshalPKIXPublicKey serializes a public key to PKIX DER format. Supports SM2 public keys via gmsm/smx509.
func MarshalPrivateKey ¶ added in v0.1.4
MarshalPrivateKey serializes a private key to DER. SM2 uses PKCS#8 (with SM2 OID, via sm2.MarshalPKCS8PrivateKey); standard ECDSA uses SEC1 (x509.MarshalECPrivateKey); RSA and Ed25519 use PKCS#8.
The encoding choice is paired with PEMTypeForPrivateKey and must stay consistent with it: callers building PEM should use both together.
func NewOCSPResponseTemplate ¶
func NewOCSPResponseTemplate(cert, issuer *x509.Certificate, status int, thisUpdate, nextUpdate time.Time) (*ocsp.Response, error)
NewOCSPResponseTemplate creates an OCSP response template for a certificate. A nil cert returns an error: the template must carry the serial number of the certificate being responded about, and dereferencing a nil cert would panic.
The template's IssuerHash is left zero; both signing paths (createSM2OCSPResponse and x/crypto's CreateResponse) then default the CertID hash to SHA-256, since ocsp.Response.IssuerHash (crypto.Hash) cannot express SM3. SM3-CertID responses are produced by third-party GM responders only; when parsing such a response the parser reports IssuerHash = crypto.SHA256 — see IsSM3CertID for how to distinguish SM3 before recomputing CertID hashes.
func OCSPErrorResponse ¶ added in v0.5.0
OCSPErrorResponse builds a responseStatus-only OCSP response (no responseBytes), per RFC 6960 §4.2.1 error handling. status is one of the x/crypto/ocsp response statuses: MalformedRequest(1), InternalError(2), TryLater(3), SigRequired(5), Unauthorized(6).
func PEMTypeForPrivateKey ¶ added in v0.1.4
PEMTypeForPrivateKey returns the PEM block type for a private key. SM2, RSA and Ed25519 return pemTypePrivateKey (PKCS#8); standard ECDSA returns "EC PRIVATE KEY" (SEC1). Paired with MarshalPrivateKey.
func ParseCertificate ¶
func ParseCertificate(der []byte) (*x509.Certificate, error)
ParseCertificate parses a DER-encoded certificate.
gmsm/smx509 is tried first because it is a strict superset of crypto/x509 (it handles RSA/ECDSA/Ed25519/SM2/SM9), so routing SM2 deterministically to the gmsm backend avoids relying on crypto/x509's version-dependent behavior for SM2 OIDs and skips a wasted parse attempt. crypto/x509 remains as a fallback for ASN.1 edge cases gmsm may not yet support.
The returned certificate is a stdlib *x509.Certificate. Since SM2 certs cannot be parsed by stdlib (unsupported curve), when smx509 succeeds the result is converted to stdlib via field copy (copyCertFields) rather than re-parsing the DER through stdlib. gmsm v0.44 removed the ToX509() bridge, so the conversion is done by reflection.
On failure the returned error wraps BOTH the gmsm and stdlib parse errors (joined via errors.Join) so a debugger can see why each backend rejected the input without re-running the parsers manually. The two errors are also distinguishable programmatically via errors.Is/as against the underlying smx509 / x509 error types.
func ParseCertificatePEM ¶
func ParseCertificatePEM(pemData []byte) (*x509.Certificate, error)
ParseCertificatePEM parses a PEM-encoded certificate.
Rejects non-CERTIFICATE PEM block types (e.g. PRIVATE KEY) up front rather than feeding arbitrary block bytes to ParseCertificate and producing a confusing ASN.1 error. Matches the ParseCertificatePEM contract in the pollux cert package.
func ParseCertificateRequest ¶
func ParseCertificateRequest(der []byte) (*x509.CertificateRequest, error)
ParseCertificateRequest parses a DER-encoded CSR. gmsm/smx509 is tried first (crypto/x509 superset), see ParseCertificate. When smx509 succeeds, the result is field-copied to stdlib (smx509 CSRs with SM2 keys cannot be re-parsed by stdlib); ToX509() bridge gone since gmsm v0.44.
On failure the returned error wraps BOTH the gmsm and stdlib parse errors (same pattern as ParseCertificate) so a debugger can see why each backend rejected the input without re-running the parsers manually.
func ParseECPrivateKey ¶
func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error)
ParseECPrivateKey parses an EC (including SM2) private key from DER format.
func ParseInvalidityDate ¶ added in v0.1.4
ParseInvalidityDate extracts the InvalidityDate from a CRL entry's extensions. Returns (zero time, false) if the extension is absent or unparseable.
func ParseOCSPRequest ¶
ParseOCSPRequest parses a DER-encoded OCSP request.
func ParseOCSPResponse
deprecated
ParseOCSPResponse parses a DER-encoded OCSP response WITHOUT signature verification.
Deprecated: this function does not verify the OCSP response signature, allowing an attacker to forge a "Good" status. Use ParseOCSPResponseWithIssuer instead, which validates the signature against the issuer certificate. For legitimate parse-only use cases (logging, debugging, already-verified responses), use ParseOCSPResponseUnverified, whose name makes the security trade-off explicit at the call site.
func ParseOCSPResponseUnverified ¶ added in v0.1.4
ParseOCSPResponseUnverified parses a DER-encoded OCSP response WITHOUT signature verification. The returned Response MUST NOT be trusted for security decisions — without verification, an attacker can forge an arbitrary status (Good/Revoked/Unknown).
This is intended only for:
- Logging/inspection of a response that has already been verified by ParseOCSPResponseWithIssuer in the same request.
- Debugging/test tooling that intentionally inspects untrusted input.
For any security-relevant code path, use ParseOCSPResponseWithIssuer.
func ParseOCSPResponseWithIssuer ¶
ParseOCSPResponseWithIssuer parses and verifies a DER-encoded OCSP response. The issuer certificate is used to verify the OCSP response signature.
For SM2-signed responses, the SM2-aware verification path is used (the stdlib ocsp.ParseResponse rejects sm2.P256() with "unsupported elliptic curve"); for standard algorithms, it delegates to ocsp.ParseResponse.
In addition to signature verification, this function enforces a validity-period check: the response is rejected if NextUpdate has passed or ThisUpdate is in the future (beyond a small clock-skew tolerance). A signature-valid but stale response can otherwise be replayed to mask a revocation. Use ParseOCSPResponseWithIssuerAt to supply a reference time (e.g. for testing or a fixed verification instant).
Returns an error if issuer is nil, as signature verification would be skipped.
func ParseOCSPResponseWithIssuerAt ¶ added in v0.4.1
func ParseOCSPResponseWithIssuerAt(data []byte, issuer *x509.Certificate, now time.Time) (*ocsp.Response, error)
ParseOCSPResponseWithIssuerAt is like ParseOCSPResponseWithIssuer but uses the supplied now as the reference time for the validity-period check. Pass time.Time{} (the zero value) to disable the time check — intended only for parsing already-trusted or historical responses where staleness is not meaningful.
SM3 CertIDs: if the response's CertID hashes with SM3 (GM/T 0009-2012), resp.IssuerHash is reported as crypto.SHA256 — x/crypto's ocsp.Response cannot express SM3 (no crypto.Hash constant exists). Do NOT recompute CertID hashes from resp.IssuerHash for such a response; distinguish it with IsSM3CertID(resp) and hash with github.com/iuboy/pollux-go/sm3.
func ParsePKCS8PrivateKey ¶ added in v0.1.4
ParsePKCS8PrivateKey parses a PKCS#8 private key DER, SM2-aware: unlike crypto/x509.ParsePKCS8PrivateKey (which rejects the SM2 OID), this delegates to gmsm/smx509 and returns *sm2.PrivateKey for SM2 keys. For standard algorithms it returns the same types as x509.ParsePKCS8PrivateKey.
Use this whenever the input might be SM2. For PEM input, use ParsePrivateKeyPEM.
func ParsePKIXPublicKey ¶ added in v0.4.4
ParsePKIXPublicKey parses a PKIX-encoded public key, SM2-aware. Inverse of MarshalPKIXPublicKey. Returns *ecdsa.PublicKey for SM2/ECDSA, *rsa.PublicKey for RSA, ed25519.PublicKey for Ed25519.
func ParsePrivateKeyPEM ¶ added in v0.1.4
ParsePrivateKeyPEM parses a PEM-encoded private key, auto-detecting SM2 (PKCS#8 with SM2 OID, or SEC1 "EC PRIVATE KEY" on the SM2 P256 curve) and standard algorithms (RSA/ECDSA/Ed25519 across PKCS#8, PKCS#1, EC SEC1).
Returns *sm2.PrivateKey for SM2, or the standard crypto/x509 types (*rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey) for others. Encrypted PEMs are rejected with a clear error; decrypt first with DecryptPEMPrivateKey.
This is the recommended single entry point for private-key parsing in mixed SM2 / standard environments. Callers should not inline their own pem.Decode + x509.Parse* fallback chains.
func PublicKeyAlgorithmForPrivateKey ¶
func PublicKeyAlgorithmForPrivateKey(key any) x509.PublicKeyAlgorithm
PublicKeyAlgorithmForPrivateKey returns the appropriate public key algorithm for the given private key type.
func ResponseNonce ¶ added in v0.5.0
ResponseNonce extracts the id-pkix-OCSP-noarch nonce from a DER-encoded OCSP response's responseExtensions. It is the parsing counterpart of CreateOCSPResponseExt's Nonce field: a client that sent a nonce uses it to bind the response to its request (RFC 6960 §4.4.1: on mismatch the response MUST be rejected as replayed/forged).
func SignatureAlgorithmForPrivateKey ¶
func SignatureAlgorithmForPrivateKey(key any) x509.SignatureAlgorithm
SignatureAlgorithmForPrivateKey returns the appropriate signature algorithm for the given private key type.
func ToSMX509Certificate ¶ added in v0.4.1
func ToSMX509Certificate(cert *x509.Certificate) (*smx509.Certificate, error)
ToSMX509Certificate converts a stdlib *x509.Certificate to *smx509.Certificate. This is required since gmsm v0.44 made smx509 a clean fork: its Certificate type is no longer struct-assignable from crypto/x509's (the ToX509/FromX509 helpers and direct casts were removed).
Two cases:
- Signed certificate (Raw populated): re-parse the DER via gmsm first (lossless), falling back to stdlib x509.ParseCertificate + reflection copy — the same gmsm-then-stdlib dual-backend order as ParseCertificate, so a DER the fork rejects but stdlib accepts still converts. When both backends reject the DER the two errors are joined (errors.Join), also matching ParseCertificate.
- Template (Raw empty, e.g. passed to CreateCertificate before signing): reflection-based field copy. smx509.Certificate is a superset of the stdlib layout with the same field names; enum-typed fields (SignatureAlgorithm, PublicKeyAlgorithm, KeyUsage, ExtKeyUsage) are all int-backed with identical constant values, so they convert directly. Fields absent on one side are skipped. This avoids maintaining a brittle hand-written field list against a moving stdlib/smx509 fork baseline.
Maintenance note: this reflection-based copy assumes smx509.Certificate stays a superset of crypto/x509.Certificate with matching field names/types. If a gmsm upgrade changes the field layout (adds/removes/renames fields, or changes enum backing), re-run the round-trip and CA-chain tests (smx509/ca_chain_test.go) to confirm ToSMX509Certificate / ToStdCertificate remain lossless for every field a GM certificate uses.
func ToSMX509Certificates ¶ added in v0.4.1
func ToSMX509Certificates(certs []*x509.Certificate) ([]*smx509.Certificate, error)
ToSMX509Certificates converts a slice of stdlib *x509.Certificate to []*smx509.Certificate (batch form of ToSMX509Certificate). A nil/empty input returns an empty (non-nil) slice. On error, the index of the failing cert is wrapped into the returned error.
func ToStdCertificate ¶ added in v0.5.0
func ToStdCertificate(smCert *smx509.Certificate) (*x509.Certificate, error)
ToStdCertificate converts a gmsm *smx509.Certificate to a stdlib *x509.Certificate via reflection-based field copy (see copyCertFields). This replaces the ToX509() bridge removed in gmsm v0.44. The Raw DER is preserved, so callers that re-marshal (e.g. x509.MarshalX509) get identical bytes. SM2 public keys survive as *ecdsa.PublicKey in the any-typed PublicKey field — stdlib never needs to re-parse the curve.
func ToStdCertificates ¶ added in v0.5.0
func ToStdCertificates(certs []*smx509.Certificate) ([]*x509.Certificate, error)
ToStdCertificates converts a slice of gmsm *smx509.Certificate to []*x509.Certificate (batch form of ToStdCertificate). A nil/empty input returns an empty (non-nil) slice. On error, the index of the failing cert is wrapped into the returned error.
func ValidateKeyIdentifiers ¶ added in v0.1.4
func ValidateKeyIdentifiers(cert *x509.Certificate) (bool, []string)
ValidateKeyIdentifiers checks that a certificate's SKI/AKI conform to RFC 5280 expectations. Returns (ok, issues) where issues lists human-readable problem descriptions. Self-signed certificates (Subject == Issuer by DER) are not required to have an AKI.
func Verify ¶
func Verify(cert *x509.Certificate, opts VerifyOptions) error
Verify verifies a certificate, automatically selecting the standard library or gmsm/smx509 backend based on the key type.
func VerifyDualCerts ¶
func VerifyDualCerts(signCert, encCert *x509.Certificate) error
VerifyDualCerts verifies a TLCP dual certificate pair (sign + encrypt). It checks pairing constraints: same issuer, same subject, correct key usage. Chain verification is the caller's responsibility (each cert verified against its own root pool separately).
func VerifyOCSPResponseNonce ¶ added in v0.5.0
VerifyOCSPResponseNonce enforces the full RFC 6960 §4.4.1 nonce binding for a CLIENT that sent a nonce:
- the response MUST carry a nonce (a response without one is replayable and MUST be rejected — the classic stripping attack where a MITM removes the request extension and replays an old window-valid response);
- the echoed nonce MUST equal the sent nonce (constant-time compare — nonce equality gates trust decisions);
- the nonce MUST be at least minOCSPNonceLen bytes.
sentNonce itself must be at least minOCSPNonceLen (generate with crypto/rand). Pass nil only when no nonce was sent (no-op).
Types ¶
type CRLReason ¶ added in v0.1.4
type CRLReason int
CRLReason is the CRLReason enumerated type from RFC 5280 §5.3.1. Values are fixed explicit constants: value 7 is reserved by RFC 5280 and must not be used, so iota-style implicit numbering is avoided.
const ( ReasonUnspecified CRLReason = 0 // unspecified ReasonKeyCompromise CRLReason = 1 // keyCompromise ReasonCACompromise CRLReason = 2 // cACompromise ReasonAffiliationChanged CRLReason = 3 // affiliationChanged ReasonSuperseded CRLReason = 4 // superseded ReasonCessationOfOperation CRLReason = 5 // cessationOfOperation ReasonCertificateHold CRLReason = 6 // certificateHold // Value 7 is unused in RFC 5280 §5.3.1 and must not be defined. ReasonRemoveFromCRL CRLReason = 8 // removeFromCRL ReasonPrivilegeWithdrawn CRLReason = 9 // privilegeWithdrawn ReasonAACompromise CRLReason = 10 // aACompromise )
func ParseCRLReason ¶ added in v0.1.4
ParseCRLReason extracts the CRLReason from a CRL entry's extensions. Returns (ReasonUnspecified, false) if the extension is absent or the value is outside the RFC 5280 §5.3.1 valid range (0-10, excluding 7).
type CertPool ¶
type CertPool struct {
// contains filtered or unexported fields
}
CertPool is a set of SM2-aware certificates that preserves raw DER bytes. Unlike x509.CertPool, it retains the original DER encoding so that certificates can be re-parsed with gmsm/smx509 without loss.
func (*CertPool) AddCert ¶
func (p *CertPool) AddCert(cert *x509.Certificate)
AddCert adds a certificate to the pool. It stores both the parsed certificate and its raw DER bytes.
func (*CertPool) AppendCertsFromPEM ¶
AppendCertsFromPEM parses PEM-encoded certificates and adds them to the pool. Returns true if at least one certificate was successfully parsed.
func (*CertPool) Certificates ¶
func (p *CertPool) Certificates() []*x509.Certificate
Certificates returns all certificates in the pool.
type OCSPResponseParams ¶ added in v0.5.0
type OCSPResponseParams struct {
Status int // ocsp.Good / ocsp.Revoked / ocsp.Unknown
SerialNumber *big.Int
ThisUpdate time.Time
NextUpdate time.Time
RevokedAt time.Time
RevocationReason int
// Certificate is the responder certificate embedded in the response
// (nil omits the certificates field).
Certificate *x509.Certificate
// IssuerHash selects the CertID hash (echo the request's HashAlgorithm).
// Zero defaults to SHA-256.
IssuerHash crypto.Hash
// Nonce, when non-empty, is echoed as an id-pkix-OCSP-noarch
// responseExtension (RFC 6960 §4.4.1). Responders MUST echo the exact
// request nonce to bind the response to the request (anti-replay).
// Nonces shorter than 16 bytes are rejected (RFC 8954 §2.3 floor):
// a 2-byte nonce has effectively no binding strength.
Nonce []byte
// ExtraExtensions are appended to responseExtensions verbatim, after the
// Nonce extension (caller is responsible for OID uniqueness).
ExtraExtensions []pkix.Extension
}
OCSPResponseParams is the parameter set for CreateOCSPResponseExt. It is a controlled superset of x/crypto's ocsp.Response; a standalone type is required because ocsp.Response has no field for response-level extensions (where the RFC 6960 §4.4.1 nonce must live).
type VerifyOptions ¶
type VerifyOptions struct {
DNSName string
Roots *CertPool
Intermediates *CertPool
// KeyUsages specifies the extended key usages the certificate must satisfy.
// If nil, defaults to ExtKeyUsageServerAuth (matching crypto/x509 default).
// Set to []ExtKeyUsage{ExtKeyUsageClientAuth} when verifying client certs.
KeyUsages []x509.ExtKeyUsage
// CurrentTime is used as the reference time for certificate validity
// (NotBefore/NotAfter) checks. If zero, time.Now() is used. Set this for
// deterministic testing, fixed verification instants, or clock-skew
// tolerance. The standard-library path forwards it to x509.VerifyOptions;
// the SM2 path applies it manually (gmsm/smx509 does not support
// CurrentTime), matching the cert package's behavior.
//
// SM2-path limitation: gmsm's chain verification internally uses the wall
// clock, so CurrentTime only gates the LEAF certificate (checked after
// chain verification). A historical instant where the leaf was valid but
// is now expired still fails inside gmsm first; intermediates/roots are
// always checked against the wall clock on this path.
CurrentTime time.Time
}
VerifyOptions holds certificate verification options.