| // Copyright 2020 The Monogon Project Authors. |
| // |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // I've fixed this upstream, compat is going away once |
| // https://go-review.googlesource.com/c/go/+/204046 hits stable |
| package ca |
| |
| import ( |
| "crypto" |
| "crypto/x509" |
| "crypto/x509/pkix" |
| "encoding/asn1" |
| "errors" |
| "io" |
| "time" |
| ) |
| |
| // Workaround for Go not supporting Ed25519 CRLs |
| type CompatCertificate x509.Certificate |
| |
| var oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} |
| var oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} |
| |
| func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { |
| sigAlgo.Algorithm = oidSignatureEd25519 |
| return |
| } |
| |
| // RFC 5280, 4.2.1.1 |
| type authKeyId struct { |
| Id []byte `asn1:"optional,tag:0"` |
| } |
| |
| // CreateCRL returns a DER encoded CRL, signed by this Certificate, that |
| // contains the given list of revoked certificates. |
| func (c *CompatCertificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { |
| key, ok := priv.(crypto.Signer) |
| if !ok { |
| return nil, errors.New("x509: certificate private key does not implement crypto.Signer") |
| } |
| |
| hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) |
| if err != nil { |
| return nil, err |
| } |
| |
| // Force revocation times to UTC per RFC 5280. |
| revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) |
| for i, rc := range revokedCerts { |
| rc.RevocationTime = rc.RevocationTime.UTC() |
| revokedCertsUTC[i] = rc |
| } |
| |
| tbsCertList := pkix.TBSCertificateList{ |
| Version: 1, |
| Signature: signatureAlgorithm, |
| Issuer: c.Subject.ToRDNSequence(), |
| ThisUpdate: now.UTC(), |
| NextUpdate: expiry.UTC(), |
| RevokedCertificates: revokedCertsUTC, |
| } |
| |
| // Authority Key Id |
| if len(c.SubjectKeyId) > 0 { |
| var aki pkix.Extension |
| aki.Id = oidExtensionAuthorityKeyId |
| aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) |
| if err != nil { |
| return |
| } |
| tbsCertList.Extensions = append(tbsCertList.Extensions, aki) |
| } |
| |
| tbsCertListContents, err := asn1.Marshal(tbsCertList) |
| if err != nil { |
| return |
| } |
| |
| signed := tbsCertListContents |
| if hashFunc != 0 { |
| h := hashFunc.New() |
| h.Write(signed) |
| signed = h.Sum(nil) |
| } |
| |
| var signature []byte |
| signature, err = key.Sign(rand, signed, hashFunc) |
| if err != nil { |
| return |
| } |
| |
| return asn1.Marshal(pkix.CertificateList{ |
| TBSCertList: tbsCertList, |
| SignatureAlgorithm: signatureAlgorithm, |
| SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |
| }) |
| } |