186 lines
3.5 KiB
Go
186 lines
3.5 KiB
Go
|
package pemfile
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"crypto/rsa"
|
||
|
"crypto/x509"
|
||
|
"encoding/pem"
|
||
|
"errors"
|
||
|
"io/fs"
|
||
|
"os"
|
||
|
|
||
|
"src.lwithers.me.uk/go/writefile"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
TypePKCS1PrivateKey = "RSA PRIVATE KEY"
|
||
|
TypePKCS8PrivateKey = "PRIVATE KEY"
|
||
|
TypePKCS1PublicKey = "RSA PUBLIC KEY"
|
||
|
TypePKIXPublicKey = "PUBLIC KEY"
|
||
|
TypeX509Certificate = "CERTIFICATE"
|
||
|
TypeX509CSR = "CERTIFICATE REQUEST"
|
||
|
TypeX509CRL = "X509 CRL"
|
||
|
)
|
||
|
|
||
|
func Write(filename, typ string, der []byte) error {
|
||
|
finalFname, f, err := writefile.New(filename)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer writefile.Abort(f)
|
||
|
|
||
|
out := bufio.NewWriter(f)
|
||
|
pem.Encode(out, &pem.Block{
|
||
|
Type: typ,
|
||
|
Bytes: der,
|
||
|
})
|
||
|
if err = out.Flush(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return writefile.Commit(finalFname, f)
|
||
|
}
|
||
|
|
||
|
func ReadKey(filename string) (*rsa.PrivateKey, error) {
|
||
|
raw, err := os.ReadFile(filename)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
block, rest := pem.Decode(raw)
|
||
|
raw = rest
|
||
|
switch {
|
||
|
case block == nil:
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "decode",
|
||
|
Path: filename,
|
||
|
Err: errors.New("no private key PEM block found"),
|
||
|
}
|
||
|
|
||
|
case block.Type == TypePKCS1PrivateKey:
|
||
|
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse key",
|
||
|
Path: filename,
|
||
|
Err: err,
|
||
|
}
|
||
|
}
|
||
|
return key, nil
|
||
|
|
||
|
case block.Type == TypePKCS8PrivateKey:
|
||
|
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse key",
|
||
|
Path: filename,
|
||
|
Err: err,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rsakey, ok := key.(*rsa.PrivateKey)
|
||
|
if !ok {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse key",
|
||
|
Path: filename,
|
||
|
Err: errors.New("not an RSA key"),
|
||
|
}
|
||
|
}
|
||
|
return rsakey, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func ReadCert(filename string) (*x509.Certificate, error) {
|
||
|
raw, err := os.ReadFile(filename)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
block, rest := pem.Decode(raw)
|
||
|
raw = rest
|
||
|
switch {
|
||
|
case block == nil:
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "decode",
|
||
|
Path: filename,
|
||
|
Err: errors.New("no certificate PEM block found"),
|
||
|
}
|
||
|
|
||
|
case block.Type == TypeX509Certificate:
|
||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse cert",
|
||
|
Path: filename,
|
||
|
Err: err,
|
||
|
}
|
||
|
}
|
||
|
return cert, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func ReadCRL(filename string) (*x509.RevocationList, error) {
|
||
|
raw, err := os.ReadFile(filename)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
block, rest := pem.Decode(raw)
|
||
|
raw = rest
|
||
|
switch {
|
||
|
case block == nil:
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "decode",
|
||
|
Path: filename,
|
||
|
Err: errors.New("no CRL PEM block found"),
|
||
|
}
|
||
|
|
||
|
case block.Type == TypeX509CRL:
|
||
|
crl, err := x509.ParseRevocationList(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse cert",
|
||
|
Path: filename,
|
||
|
Err: err,
|
||
|
}
|
||
|
}
|
||
|
return crl, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func ReadCSR(filename string) (*x509.CertificateRequest, error) {
|
||
|
raw, err := os.ReadFile(filename)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
block, rest := pem.Decode(raw)
|
||
|
raw = rest
|
||
|
switch {
|
||
|
case block == nil:
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "decode",
|
||
|
Path: filename,
|
||
|
Err: errors.New("no CSR PEM block found"),
|
||
|
}
|
||
|
|
||
|
case block.Type == TypeX509CSR:
|
||
|
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||
|
if err != nil {
|
||
|
return nil, &fs.PathError{
|
||
|
Op: "parse CSR",
|
||
|
Path: filename,
|
||
|
Err: err,
|
||
|
}
|
||
|
}
|
||
|
return csr, nil
|
||
|
}
|
||
|
}
|
||
|
}
|