/* * Copyright (C) 2020-2022, IrineSistiana * * This file is part of mosdns. * * mosdns is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mosdns is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package utils import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "math/big" "os" "time" ) // LoadCertPool reads and loads certificates in certs. func LoadCertPool(certs []string) (*x509.CertPool, error) { rootCAs := x509.NewCertPool() for _, cert := range certs { b, err := os.ReadFile(cert) if err != nil { return nil, err } if ok := rootCAs.AppendCertsFromPEM(b); !ok { return nil, fmt.Errorf("no certificate was successfully parsed in %s", cert) } } return rootCAs, nil } // GenerateCertificate generates an ecdsa certificate with given dnsName. // This should only use in test. func GenerateCertificate(dnsName string) (cert tls.Certificate, err error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return } //serial number serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { err = fmt.Errorf("generate serial number: %w", err) return } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{CommonName: dnsName}, DNSNames: []string{dnsName}, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) if err != nil { return } b, err := x509.MarshalPKCS8PrivateKey(key) if err != nil { return } keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: b}) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) return tls.X509KeyPair(certPEM, keyPEM) } // ClosedChan returns true if c is closed. // c must not use for sending data and must be used in close() only. // If ClosedChan receives something from c, it panics. func ClosedChan(c chan struct{}) bool { select { case _, ok := <-c: if !ok { return true } panic("received from the chan") default: return false } }