rsa/pkg/pemfile/pemfile.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
}
}
}