In x509.CreateCertificate, how do you self-sign rather than sign with a CA parent?
answer
- one argument decides who signed it
- the degenerate case is the same value twice
- the issuer name is copied, never typed in
- signing key and embedded key differ
- self-signed still is not automatically a CA
basics
~20 sPass the same template value as both the template and the parent argument, and sign with the private key matching the certificate's own public key. Any other parent means that parent's private key signs, and its Subject becomes the new certificate's Issuer.
solid answer
~40 s`CreateCertificate(rand, template, parent, pub, priv)` self-signs when `template` and `parent` are the same `*x509.Certificate` and `priv` matches the `pub` you passed — that is how you bootstrap a root. To issue from a CA instead, `parent` is the CA's certificate and `priv` is the CA's private key, while `pub` is the subject's. The parent contributes real content: its `Subject` becomes the new certificate's `Issuer`, and its `SubjectKeyId` becomes the child's `AuthorityKeyId` if the template did not set one, which is what lets a verifier walk the chain. The signature algorithm is derived from the signing key's type unless you set `template.SignatureAlgorithm`. Note that self-signed is not the same as CA: a root still needs `IsCA` and `BasicConstraintsValid` set to be allowed to sign anything else.
code
go · 5 lines// root: template is its own parent, signed by its own key
rootDER, err := x509.CreateCertificate(rand.Reader, &rootTmpl, &rootTmpl, &rootKey.PublicKey, rootKey)
// leaf: parent is the parsed root, signed by the root's key
leafDER, err := x509.CreateCertificate(rand.Reader, &leafTmpl, rootCert, &leafKey.PublicKey, rootKey)go deeper
Recall the rule: same value for template and parent, plus the certificate's own private key, gives a self-signed certificate. Otherwise the parent's certificate and the parent's private key are what you pass.
Explain what the parent supplies — the issuer name from its subject, the authority key identifier from its subject key identifier, and the signature from its key — and why you never set the Issuer field yourself.
Show that you know self-signed and CA are different properties, and that a service issuing from CSRs must verify the request signature and copy only policy-approved fields rather than honouring what a client asked for.
Own the question of where the signing key lives and who may reach it: whether the root ever comes online, whether the issuing intermediate is per-environment, and what the recovery story is when a signing key must be replaced.
## Two arguments, one relationship `x509.CreateCertificate` takes both a `template` and a `parent`. The template describes the certificate being created; the parent describes the certificate doing the creating. That single distinction covers every shape an internal issuing service needs. **Self-signed.** Pass the same template value in both positions and sign with the key that matches the public key you are embedding: ``` der, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, &key.PublicKey, key) ``` The resulting certificate has `Issuer == Subject` and is verifiable only by itself. This is how you bootstrap a root of trust: there is no one above it, so it vouches for itself, and trust comes from the fact that operators install it deliberately rather than from any cryptographic property. **Signed by a parent.** Pass the issuer's parsed certificate as `parent` and the issuer's private key as `priv`: ``` der, err := x509.CreateCertificate(rand.Reader, &leafTmpl, caCert, &leafKey.PublicKey, caKey) ``` Now three different objects are in play — the leaf's template, the leaf's public key, and the CA's certificate plus its private key — and getting them confused is the usual source of a chain that will not verify. ## What the parent actually contributes It is worth being concrete, because people often assume they must fill in the `Issuer` field by hand. They must not. - **Issuer name.** The encoded certificate's issuer is taken from the parent's subject (its raw, byte-for-byte encoded subject, so the name matches exactly what a verifier will compare against). Anything you put in `template.Issuer` is ignored. - **Authority Key Identifier.** If `template.AuthorityKeyId` is empty and the parent has a `SubjectKeyId`, the child gets the parent's `SubjectKeyId` as its AKI. This is the hint that lets a verifier find the right issuer quickly when several candidates share a name. - **Subject Key Identifier.** If the template does not set `SubjectKeyId` and the template is a CA, Go derives one from the public key being certified, so intermediates chain cleanly without you doing anything. - **The signature itself.** The bytes are signed by `priv`, and the algorithm is chosen from that key's type — ECDSA P-256 gives an ECDSA-SHA256 signature, and so on — unless `template.SignatureAlgorithm` names something else explicitly. Because the issuer name comes from the parent, a self-signed certificate is exactly the degenerate case: parent is template, so issuer is subject. ## Self-signed is not the same as being a CA This trips up almost everyone once. Self-signing describes *who signed it*. Being a CA describes *what it is allowed to sign*. A self-signed certificate with `IsCA` false and no `BasicConstraintsValid` is a perfectly well-formed end-entity certificate that happens to vouch for itself — useful for a throwaway TLS listener, useless as a root. A root that is meant to issue must set `IsCA: true` **and** `BasicConstraintsValid: true`, and its `KeyUsage` must include certificate signing if it sets `KeyUsage` at all. ## Where CSRs fit An internal issuing service usually receives an `x509.CertificateRequest` rather than a bare public key. `CreateCertificate` does not read CSRs — there is no argument for one. The correct flow is: parse the request, call its `CheckSignature` method to prove the requester holds the private key, then copy *only* the fields your policy allows (typically the public key and some subset of the requested names) into a template you construct yourself. Anything the requester asked for that you copy blindly — key usages, basic constraints, arbitrary extensions — is a privilege you have handed to a client, and it is exactly how a workload-certificate service accidentally becomes a certificate-authority-issuing service. ## Practical consequence for a chain When the platform team replaces a runbook of shell commands with a small Go issuing service, the chain either verifies or it does not, and there is rarely a middle state. The two failures worth rehearsing: signing the leaf with the leaf's own key while passing the CA as `parent` (issuer name says CA, signature does not match the CA's key, and verification fails on signature check), and passing the CA's public key as `pub` (a certificate that certifies the wrong key entirely). Both compile. Both are caught instantly by a test that issues and then verifies.
- Which fields does x509.CreateCertificate take from the parent rather than from your template?The issuer name comes from the parent's encoded subject, and the child's `AuthorityKeyId` comes from the parent's `SubjectKeyId` when the template leaves it empty. The signature is produced with the signing key you pass. Whatever you write into `template.Issuer` is ignored, which is why hand-setting it is a sign someone has misunderstood the call.
- Your service receives a CSR. Does CreateCertificate use the fields the requester asked for?No — it never sees the CSR. You parse the request, call `CheckSignature` on it to prove possession of the private key, and then copy only what your policy permits into a template you build. Copying requested extensions verbatim lets a client ask to be a CA, which is a privilege escalation, not a convenience.
- Is a self-signed certificate the same thing as a root CA certificate?No. Self-signed only means the issuer and subject are the same key. To act as a CA it additionally needs `IsCA: true` together with `BasicConstraintsValid: true`, and a `KeyUsage` that permits certificate signing if `KeyUsage` is set. A self-signed end-entity certificate is common and perfectly valid.
saying these in an interview costs you the question
- Thinks passing nil as parent produces a self-signed certificate
- Fills in template.Issuer by hand and expects it to be used
- Signs a leaf with the leaf's own key while naming the CA as parent
- Believes self-signed automatically means it can issue other certificates
- Copies a CSR's requested extensions straight into the issued template