mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-09 02:55:59 +08:00
Implement mdmcert.download support in mdmctl (#401)
This commit is contained in:
@@ -8,11 +8,12 @@ import (
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenerateRandomCertificateSerialNumber() (*big.Int, error) {
|
||||
@@ -66,6 +67,11 @@ func ReadPEMCertificateFile(path string) (*x509.Certificate, error) {
|
||||
return certs[0], nil
|
||||
}
|
||||
|
||||
const (
|
||||
rsaPrivateKeyPEMBlockType = "RSA PRIVATE KEY"
|
||||
certificatePEMBlockType = "CERTIFICATE"
|
||||
)
|
||||
|
||||
func ReadPEMCertificatesFile(path string) ([]*x509.Certificate, error) {
|
||||
pemData, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -76,7 +82,7 @@ func ReadPEMCertificatesFile(path string) ([]*x509.Certificate, error) {
|
||||
for {
|
||||
var block *pem.Block
|
||||
block, rest = pem.Decode(rest)
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
if block == nil || block.Type != certificatePEMBlockType {
|
||||
return nil, errors.New("failed to decode PEM block containing certificate")
|
||||
}
|
||||
asn1data = append(asn1data, block.Bytes...)
|
||||
@@ -87,6 +93,40 @@ func ReadPEMCertificatesFile(path string) ([]*x509.Certificate, error) {
|
||||
return x509.ParseCertificates(asn1data)
|
||||
}
|
||||
|
||||
func ReadPEMRSAKeyFile(path string) (*rsa.PrivateKey, error) {
|
||||
return ReadEncryptedPEMRSAKeyFile(path, nil)
|
||||
}
|
||||
|
||||
func ReadEncryptedPEMRSAKeyFile(path string, password []byte) (*rsa.PrivateKey, error) {
|
||||
pemData, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pemBlock, _ := pem.Decode(pemData)
|
||||
if pemBlock == nil {
|
||||
return nil, errors.New("PEM decode failed")
|
||||
}
|
||||
if pemBlock.Type != rsaPrivateKeyPEMBlockType {
|
||||
return nil, fmt.Errorf("expecting PEM type of %s, but got %s", rsaPrivateKeyPEMBlockType, pemBlock.Type)
|
||||
}
|
||||
|
||||
if x509.IsEncryptedPEMBlock(pemBlock) {
|
||||
if password == nil {
|
||||
return nil, errors.New("no supplied password for encrypted PEM")
|
||||
}
|
||||
derBytes, err := x509.DecryptPEMBlock(pemBlock, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x509.ParsePKCS1PrivateKey(derBytes)
|
||||
} else if password != nil {
|
||||
return nil, errors.New("supplied PEM password, but not encrypted")
|
||||
}
|
||||
|
||||
return x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
|
||||
}
|
||||
|
||||
func WritePEMCertificateFile(cert *x509.Certificate, path string) error {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -97,7 +137,7 @@ func WritePEMCertificateFile(cert *x509.Certificate, path string) error {
|
||||
return pem.Encode(
|
||||
file,
|
||||
&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Type: certificatePEMBlockType,
|
||||
Bytes: cert.Raw,
|
||||
})
|
||||
}
|
||||
@@ -112,11 +152,31 @@ func WritePEMRSAKeyFile(key *rsa.PrivateKey, path string) error {
|
||||
return pem.Encode(
|
||||
file,
|
||||
&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Type: rsaPrivateKeyPEMBlockType,
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
||||
})
|
||||
}
|
||||
|
||||
func WriteEncryptedPEMRSAKeyFile(key *rsa.PrivateKey, password []byte, path string) error {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
encPemBlock, err := x509.EncryptPEMBlock(
|
||||
rand.Reader,
|
||||
rsaPrivateKeyPEMBlockType,
|
||||
x509.MarshalPKCS1PrivateKey(key),
|
||||
password,
|
||||
x509.PEMCipher3DES)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pem.Encode(file, encPemBlock)
|
||||
}
|
||||
|
||||
// TopicFromCert extracts the push certificate topic from the provided certificate.
|
||||
func TopicFromCert(cert *x509.Certificate) (string, error) {
|
||||
var oidASN1UserID = asn1.ObjectIdentifier{0, 9, 2342, 19200300, 100, 1, 1}
|
||||
|
||||
@@ -43,11 +43,11 @@ func CreateCSR(req *CSRConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
derBytes, err := newCSR(key, strings.ToLower(req.Email), strings.ToUpper(req.Country), req.CommonName)
|
||||
derBytes, err := NewCSR(key, strings.ToLower(req.Email), strings.ToUpper(req.Country), req.CommonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pemCSR := pemCSR(derBytes)
|
||||
pemCSR := PemCSR(derBytes)
|
||||
return ioutil.WriteFile(req.CSRPath, pemCSR, 0600)
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ const (
|
||||
)
|
||||
|
||||
// create a CSR using the same parameters as Keychain Access would produce
|
||||
func newCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error) {
|
||||
func NewCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error) {
|
||||
subj := pkix.Name{
|
||||
Country: []string{country},
|
||||
CommonName: cname,
|
||||
@@ -161,7 +161,7 @@ func newCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error)
|
||||
}
|
||||
|
||||
// convert DER to PEM format
|
||||
func pemCSR(derBytes []byte) []byte {
|
||||
func PemCSR(derBytes []byte) []byte {
|
||||
pemBlock := &pem.Block{
|
||||
Type: csrPEMBlockType,
|
||||
Headers: nil,
|
||||
|
||||
Reference in New Issue
Block a user