blob: 9c1f4a6ef9fbb9060ef66bb242f9437c71a0f0bd [file] [log] [blame]
// 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},
})
}