Allow passing in PEM MDM cert and key (#60)

closes #55
This commit is contained in:
Jesse Peterson
2016-11-16 15:38:45 -08:00
committed by Victor Vrantchan
parent fe50027f15
commit 4b867f1d04
4 changed files with 83 additions and 47 deletions

View File

@@ -53,7 +53,7 @@ func loadConfig() (*Config, error) {
// APNS config. Can be either two files or a combined .p12 (like the one exported from keychain access")
flPushCert = flag.String("push-cert", envString("MICROMDM_PUSH_CERT", ""), "path to push certificate")
flPushPass = flag.String("push-password", envString("MICROMDM_PUSH_PASSWORD", ""), "push certificate password")
flPushKey = flag.String("push-key", envString("MICROMDM_PUSH_KEY", ""), "path to push certificate private key(if not using a single .p12 file)")
flPushKey = flag.String("push-key", envString("MICROMDM_PUSH_KEY", ""), "path to push certificate private key (if not using a single .p12 file)")
)
flag.Parse()

View File

@@ -1,6 +1,11 @@
package app
import (
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"errors"
"io/ioutil"
pushcertificate "github.com/RobotsAndPencils/buford/certificate"
@@ -20,6 +25,8 @@ import (
"github.com/micromdm/micromdm/enroll"
"github.com/micromdm/micromdm/management"
"github.com/micromdm/micromdm/workflow"
"golang.org/x/crypto/pkcs12"
)
// setupServices uses the values from the config to set up the various components
@@ -33,6 +40,7 @@ func setupServices(config *Config, logger log.Logger) (*serviceManager, error) {
sm.setupWorkflowDatastore()
sm.setupCertificateDatastore()
sm.loadPushCerts()
sm.setupPushService()
sm.setupCommandService()
@@ -55,6 +63,7 @@ type serviceManager struct {
ApplicationDatastore application.Datastore
PushService *push.Service
pushServiceCert
CommandService command.Service
ManagementService management.Service
@@ -68,15 +77,80 @@ type serviceManager struct {
err error
}
type pushServiceCert struct {
*x509.Certificate
PrivateKey interface{}
}
func (s *serviceManager) loadPushCerts() {
if s.err != nil {
return
}
if s.APNS.PrivateKeyPath == "" {
var pkcs12Data []byte
pkcs12Data, s.err = ioutil.ReadFile(s.APNS.CertificatePath)
if s.err != nil {
return
}
s.pushServiceCert.PrivateKey, s.pushServiceCert.Certificate, s.err = pkcs12.Decode(pkcs12Data, s.APNS.PrivateKeyPass)
return
}
var pemData []byte
pemData, s.err = ioutil.ReadFile(s.APNS.CertificatePath)
if s.err != nil {
return
}
pemBlock, _ := pem.Decode(pemData)
if pemBlock == nil {
s.err = errors.New("invalid PEM data for cert")
return
}
s.pushServiceCert.Certificate, s.err = x509.ParseCertificate(pemBlock.Bytes)
if s.err != nil {
return
}
pemData, s.err = ioutil.ReadFile(s.APNS.PrivateKeyPath)
if s.err != nil {
return
}
pemBlock, _ = pem.Decode(pemData)
if pemBlock == nil {
s.err = errors.New("invalid PEM data for privkey")
return
}
s.pushServiceCert.PrivateKey, s.err = x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
}
var oidASN1UserID = asn1.ObjectIdentifier{0, 9, 2342, 19200300, 100, 1, 1}
func topicFromCert(cert *x509.Certificate) (string, error) {
for _, v := range cert.Subject.Names {
if v.Type.Equal(oidASN1UserID) {
return v.Value.(string), nil
}
}
return "", errors.New("Could not find Push Topic (UserID OID) in certificate")
}
func (s *serviceManager) setupEnrollmentService() {
if s.err != nil {
return
}
pushTopic, err := topicFromCert(s.pushServiceCert.Certificate)
if err != nil {
s.err = err
return
}
// TODO: clean up order of inputs. Maybe pass *SCEPConfig as an arg?
// but if you do, the packages are coupled, better not.
s.EnrollmentService, s.err = enroll.NewService(
s.APNS.CertificatePath,
s.APNS.PrivateKeyPass,
pushTopic,
s.Enrollment.CACertPath,
s.SCEP.RemoteURL,
s.SCEP.Challenge,
@@ -155,15 +229,10 @@ func (s *serviceManager) setupPushService() {
if s.err != nil {
return
}
cert, key, err := pushcertificate.Load(
s.APNS.CertificatePath,
s.APNS.PrivateKeyPass,
)
if err != nil {
s.err = err
return
}
client, err := push.NewClient(pushcertificate.TLS(cert, key))
client, err := push.NewClient(pushcertificate.TLS(
s.pushServiceCert.Certificate,
s.pushServiceCert.PrivateKey.(*rsa.PrivateKey),
))
if err != nil {
s.err = err
return

View File

@@ -1,29 +0,0 @@
package enroll
import (
"errors"
"golang.org/x/crypto/pkcs12"
"io/ioutil"
)
const PushTopicASN1 string = "0.9.2342.19200300.100.1.1"
func GetPushTopicFromPKCS12(certPath string, certPass string) (string, error) {
certData, err := ioutil.ReadFile(certPath)
if err != nil {
return "", err
}
_, cert, err := pkcs12.Decode(certData, certPass)
if err != nil {
return "", err
}
for _, v := range cert.Subject.Names {
if v.Type.String() == PushTopicASN1 {
return v.Value.(string), nil
}
}
return "", errors.New("Could not find Push Topic in the provided pkcs12 bundle.")
}

View File

@@ -10,13 +10,9 @@ type Service interface {
Enroll(ctx context.Context) (Profile, error)
}
func NewService(pushCertPath, pushCertPass, caCertPath, scepURL, scepChallenge, url, tlsCertPath, scepSubject string) (Service, error) {
pushTopic, err := GetPushTopicFromPKCS12(pushCertPath, pushCertPass)
if err != nil {
return nil, err
}
func NewService(pushTopic, caCertPath, scepURL, scepChallenge, url, tlsCertPath, scepSubject string) (Service, error) {
var caCert, tlsCert []byte
var err error
if caCertPath != "" {
caCert, err = ioutil.ReadFile(caCertPath)