Skip to content

Commit 6f7a285

Browse files
use an interface for verifying Mdm-Signature headers (#137)
1 parent 5141724 commit 6f7a285

File tree

4 files changed

+41
-8
lines changed

4 files changed

+41
-8
lines changed

cmd/nanomdm/main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/micromdm/nanomdm/certverify"
1616
"github.com/micromdm/nanomdm/cli"
17+
"github.com/micromdm/nanomdm/cryptoutil"
1718
mdmhttp "github.com/micromdm/nanomdm/http"
1819
httpapi "github.com/micromdm/nanomdm/http/api"
1920
"github.com/micromdm/nanomdm/http/authproxy"
@@ -161,7 +162,7 @@ func main() {
161162
if *flDebug {
162163
opts = append(opts, httpmdm.SigLogWithLogErrors(true))
163164
}
164-
h = httpmdm.CertExtractMdmSignatureMiddleware(h, opts...)
165+
h = httpmdm.CertExtractMdmSignatureMiddleware(h, cryptoutil.MdmSignatureVerifierFunc(cryptoutil.VerifyMdmSignature), opts...)
165166
}
166167
return h
167168
}

cryptoutil/cryptoutil.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,15 @@ func TopicFromPEMCert(pemCert []byte) (string, error) {
4040
return TopicFromCert(cert)
4141
}
4242

43-
// VerifyMdmSignature verifies an Apple MDM "Mdm-Signature" header and
44-
// returns the signing certificate.
45-
//
43+
// MdmSignatureVerifierFunc is an adapter for verifying Apple MDM "Mdm-Signature" headers.
44+
type MdmSignatureVerifierFunc func(header string, body []byte) (*x509.Certificate, error)
45+
46+
// VerifyMdmSignature calls v with header and body.
47+
func (v MdmSignatureVerifierFunc) VerifyMdmSignature(header string, body []byte) (*x509.Certificate, error) {
48+
return v(header, body)
49+
}
50+
51+
// VerifyMdmSignature verifies an Apple MDM "Mdm-Signature" header and returns the signing certificate.
4652
// See https://developer.apple.com/documentation/devicemanagement/implementing_device_management/managing_certificates_for_mdm_servers_and_devices
4753
// section "Pass an Identity Certificate Through a Proxy."
4854
func VerifyMdmSignature(header string, body []byte) (*x509.Certificate, error) {

cryptoutil/cryptoutil_test.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,29 @@ import (
77
"github.com/smallstep/pkcs7"
88
)
99

10+
const mdmSignatureHeader1 = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIDIzCCAx8wggIHoAMCAQICAQQwDQYJKoZIhvcNAQELBQAwPTETMBEGCgmSJomT8ixkARkWA2NvbTEVMBMGCgmSJomT8ixkARkWBUd1c3RvMQ8wDQYDVQQDDAZNRE0gQ0EwHhcNMjEwOTE4MTg0NTA1WhcNMjIwOTE4MTg0NTA1WjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Weag+4AQFkLrgm2/lZCdjGj5KC2rbIKdBdfExxaFWmvTtNCdXWyd5eROboRuEG/D1Zun0WKaKc1/emikBhnXP4qzEnNobx1OOfzeR1ZiazwftgAKrDZK6e4IJo15x8juRZvbjfKAQV+fw6TIGe4COUKpBtJo1idxJzI6OO2pQ6tvfzxhvbeD8VtYoHFgTXmBDHqUjmixdM+RIDUqReemaTeK5ybWTw3ZrydR7lM+I92Y9x/sRSxTODjgcczmprMVFl7a/d7biuqJtxg/RRVA85LWE3Gl+3BaVi9TC8xzaVioC++RmbXe3Z5qHmm+fkhfIzHksBW0Yn0DmWZRoWpgwIDAQABo2cwZTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFCxqnx50ZpbKaED6AAsxSScMguy6MB8GA1UdIwQYMBaAFBoyVn803d9H43znmXRJGmE066VrMA0GCSqGSIb3DQEBCwUAA4IBAQAU0jY/wjNth2fJsp49hbhEUFFPJIvM9lS5cWmSX2Xg7cK1pzDZJktA5MAZaLxbYCqpM9HegE3WhpyzaFRcIpBWV6T4R70gWbKcwn7WzAII0TBbDD4nZz2tO0kdLXA4LPyPjm/tJxzNvLfYmVNF61oImU2KXT/zp7rXOLU3KhkA4cWN9TApClTIZqlzr64T07HUA94S2ee9ia8/U2ITOswtYrGNYmky1PA9/GlcGaxm5LkthmIq4qh5/e8J8rfSXvz7GVuVqoZOBPVTQkBChG6ANCtTr8nniRIv+3L3042XjclVFj5mcLsXO5EN/v0i11ICcLs2SRJAF058CPLS7azgMYIBaTCCAWUCAQEwQjA9MRMwEQYKCZImiZPyLGQBGRYDY29tMRUwEwYKCZImiZPyLGQBGRYFR3VzdG8xDzANBgNVBAMMBk1ETSBDQQIBBDAJBgUrDgMCGgUAMA0GCSqGSIb3DQEBBQUABIIBAABiveq4A69qvK2FjCMdhm6o9aBPfTw8WiJU9I6UppTbvw1+o2OBVLAOCXw46v1SIbj7Lhq5EDm3qXLD2xkF9zd5W43PvNZFleL735De+I1IeyXOvkmElOioipDNwrRpsET6vL2zwYlE0JZuGVhr2EU8ra3czy4eAbJwvV2xHLjpvqQJZh0LNvBc10sp7Q/99qpVdCXagUPJTh68Pcua51JiUWn0tDn0eaj083Yyx+I1XNR9opYuBEVz/LwFSsUGiB9zV7KbsLikajD2+Jmues5vS2jOrmCpV+yMN3uMa4lmOlgrQoi4l62edTo45zgnEZOUle0zT2pInMgML8KiWt8AAAAAAAA="
11+
const mdmSignatureHeader2 = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIDITCCAx0wggIFoAMCAQICASIwDQYJKoZIhvcNAQELBQAwOzELMAkGA1UEBhMCVVMxDTALBgNVBAoTBHNjZXAxEDAOBgNVBAsTB1NDRVAgQ0ExCzAJBgNVBAMTAmNhMB4XDTIxMDUyODA1MDkyM1oXDTMxMDUyNjA1MDkyM1owADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1oBJs+BT6daIs7bUWib7Ji1XGpDJ9e5uPtBJ3SVj2eIStDcl9bJj5JPle8HF+WI1HQ7yIT15zu3GSN6xO6gATAk1j/vv0JFimKXa9Q017mvg5ACUcRScY1mnya7pYL9b5C/b02ubOglEMCLnekhDKJhlVTwbdC0n0ZFr6aDWZlIxHFIym28Et9F+JeRJSRCAR6jybr+nRPavxPhGnbrImBM0z6HkzbjlHDlc5g3TOrj67bjz2nT+i6isEyj1stsOeDXH4Ij3z6A3jVW12/XAsHVoaC1KqmzXV2SWuOT9oXnlxs5NxoYJYQC+XN1x604cKauLNZFHjCFOFeeubVHucCAwEAAaNnMGUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBQpqTV2kEzUfYz+4Mws1S6/D2hGnzAfBgNVHSMEGDAWgBT5TUXoM3msHybCjct8RyHuOpPr6DANBgkqhkiG9w0BAQsFAAOCAQEAMdbAM0+753sYs9erWV+QW8PTYHHTlrGaOU9VB3QaY0TG6iy/k6+l/6rYWQGW+RyElxju6xof9BVYgKb17EB0vm635PSFrAviyp495vLSFesvUUkUr7ALKC7f6H8ud3JIRhycyyih30YSlZrCwduMNjocYXPZN36hsyLeG3c977RGdHLrXFAMCvOSqHLktj/pYChR95XwrKVBaX2jtsk9B9UcDmubccPjROUKWHn3k5f2R+EJv9WVmFqNt7doG4nAAZx0ktDdgzVO7eWz/RwfFZlA9Qtm4+gG5eQd8e8HVefcCNOT/HcjfBblsOM7jzQlIvxvNss8haQ6TC//Fk/0rTGCAWcwggFjAgEBMEAwOzELMAkGA1UEBhMCVVMxDTALBgNVBAoTBHNjZXAxEDAOBgNVBAsTB1NDRVAgQ0ExCzAJBgNVBAMTAmNhAgEiMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEFBQAEggEA5h26uR27aLsghfAuDGe0mefTcxnPbqpiOFzh8t7WbK69giGQIIfs/NVqdFvYn210l2y5cAyHFVU81w6MmvqjHQJqVLptyYVDXgYy0/tsRc6Tbc+5kKD3GEkP8Z4uMCn75/8QlXFCj5DTVNWTZ8Vn/Itns51z+JYccOcsj9TnLX+0aaLz3I8X+r31Ftlx3UP6keW7HDo8m6JeGN4P3t51Dqjt08zyu72yR/gxaS91SHROypPAwMbiKqaxGiAPChgACmZDf0c/+g5T6Q0qc++cEAP9n+ViSjXyoDtS3YbfWxiiJaiieXLAiPjU9eVcXajEAwJUOJtTfECrNd5pgNpLBgAAAAAAAA=="
12+
const mdmSignatureBody2 = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+U3RhdHVzPC9rZXk+Cgk8c3RyaW5nPklkbGU8L3N0cmluZz4KCTxrZXk+VURJRDwva2V5PgoJPHN0cmluZz5ENEQ1NjA4My1CRkIwLTUwNDctOEJERi0yNzI3QkFDREM1OUI8L3N0cmluZz4KPC9kaWN0Pgo8L3BsaXN0Pgo="
13+
1014
func TestPKCS7ParseTagLengthError(t *testing.T) {
1115
// Regression test: Older versions of the library might return this BER tag length error.
12-
mdmSignatureHeader := "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIDIzCCAx8wggIHoAMCAQICAQQwDQYJKoZIhvcNAQELBQAwPTETMBEGCgmSJomT8ixkARkWA2NvbTEVMBMGCgmSJomT8ixkARkWBUd1c3RvMQ8wDQYDVQQDDAZNRE0gQ0EwHhcNMjEwOTE4MTg0NTA1WhcNMjIwOTE4MTg0NTA1WjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Weag+4AQFkLrgm2/lZCdjGj5KC2rbIKdBdfExxaFWmvTtNCdXWyd5eROboRuEG/D1Zun0WKaKc1/emikBhnXP4qzEnNobx1OOfzeR1ZiazwftgAKrDZK6e4IJo15x8juRZvbjfKAQV+fw6TIGe4COUKpBtJo1idxJzI6OO2pQ6tvfzxhvbeD8VtYoHFgTXmBDHqUjmixdM+RIDUqReemaTeK5ybWTw3ZrydR7lM+I92Y9x/sRSxTODjgcczmprMVFl7a/d7biuqJtxg/RRVA85LWE3Gl+3BaVi9TC8xzaVioC++RmbXe3Z5qHmm+fkhfIzHksBW0Yn0DmWZRoWpgwIDAQABo2cwZTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFCxqnx50ZpbKaED6AAsxSScMguy6MB8GA1UdIwQYMBaAFBoyVn803d9H43znmXRJGmE066VrMA0GCSqGSIb3DQEBCwUAA4IBAQAU0jY/wjNth2fJsp49hbhEUFFPJIvM9lS5cWmSX2Xg7cK1pzDZJktA5MAZaLxbYCqpM9HegE3WhpyzaFRcIpBWV6T4R70gWbKcwn7WzAII0TBbDD4nZz2tO0kdLXA4LPyPjm/tJxzNvLfYmVNF61oImU2KXT/zp7rXOLU3KhkA4cWN9TApClTIZqlzr64T07HUA94S2ee9ia8/U2ITOswtYrGNYmky1PA9/GlcGaxm5LkthmIq4qh5/e8J8rfSXvz7GVuVqoZOBPVTQkBChG6ANCtTr8nniRIv+3L3042XjclVFj5mcLsXO5EN/v0i11ICcLs2SRJAF058CPLS7azgMYIBaTCCAWUCAQEwQjA9MRMwEQYKCZImiZPyLGQBGRYDY29tMRUwEwYKCZImiZPyLGQBGRYFR3VzdG8xDzANBgNVBAMMBk1ETSBDQQIBBDAJBgUrDgMCGgUAMA0GCSqGSIb3DQEBBQUABIIBAABiveq4A69qvK2FjCMdhm6o9aBPfTw8WiJU9I6UppTbvw1+o2OBVLAOCXw46v1SIbj7Lhq5EDm3qXLD2xkF9zd5W43PvNZFleL735De+I1IeyXOvkmElOioipDNwrRpsET6vL2zwYlE0JZuGVhr2EU8ra3czy4eAbJwvV2xHLjpvqQJZh0LNvBc10sp7Q/99qpVdCXagUPJTh68Pcua51JiUWn0tDn0eaj083Yyx+I1XNR9opYuBEVz/LwFSsUGiB9zV7KbsLikajD2+Jmues5vS2jOrmCpV+yMN3uMa4lmOlgrQoi4l62edTo45zgnEZOUle0zT2pInMgML8KiWt8AAAAAAAA="
13-
p7signature, _ := base64.StdEncoding.DecodeString(mdmSignatureHeader)
16+
p7signature, _ := base64.StdEncoding.DecodeString(mdmSignatureHeader1)
1417

1518
_, err := pkcs7.Parse(p7signature)
1619

1720
if err != nil {
1821
t.Error("pkcs7.Parse() failed with error:", err)
1922
}
2023
}
24+
25+
func TestMdmVerifierFunc(t *testing.T) {
26+
body, err := base64.StdEncoding.DecodeString(mdmSignatureBody2)
27+
if err != nil {
28+
t.Error(err)
29+
}
30+
verifier := MdmSignatureVerifierFunc(VerifyMdmSignature)
31+
_, err = verifier.VerifyMdmSignature(mdmSignatureHeader2, body)
32+
if err != nil {
33+
t.Error(err)
34+
}
35+
}

http/mdm/mdm_cert.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,25 @@ func SigLogWithLogErrors(errors bool) SigLogOption {
100100
}
101101
}
102102

103+
// MdmSignatureVerifier verifies Apple Mdm-Signature headers and extracts certificates.
104+
type MdmSignatureVerifier interface {
105+
// VerifyMdmSignature verifies an Apple MDM "Mdm-Signature" header and returns the signing certificate.
106+
// See https://developer.apple.com/documentation/devicemanagement/implementing_device_management/managing_certificates_for_mdm_servers_and_devices
107+
// section "Pass an Identity Certificate Through a Proxy."
108+
VerifyMdmSignature(header string, body []byte) (*x509.Certificate, error)
109+
}
110+
103111
// CertExtractMdmSignatureMiddleware extracts the MDM enrollment
104112
// identity certificate from the request into the HTTP request context.
105113
// It tries to verify the Mdm-Signature header on the request.
106114
//
107115
// This middleware does not error if a certificate is not found. It
108116
// will, however, error with an HTTP 400 status if the signature
109117
// verification fails.
110-
func CertExtractMdmSignatureMiddleware(next http.Handler, opts ...SigLogOption) http.HandlerFunc {
118+
func CertExtractMdmSignatureMiddleware(next http.Handler, verifier MdmSignatureVerifier, opts ...SigLogOption) http.HandlerFunc {
119+
if verifier == nil {
120+
panic("nil verifier")
121+
}
111122
config := &sigLogConfig{logger: log.NopLogger}
112123
for _, opt := range opts {
113124
opt(config)
@@ -129,7 +140,7 @@ func CertExtractMdmSignatureMiddleware(next http.Handler, opts ...SigLogOption)
129140
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
130141
return
131142
}
132-
cert, err := cryptoutil.VerifyMdmSignature(mdmSig, b)
143+
cert, err := verifier.VerifyMdmSignature(mdmSig, b)
133144
if err != nil {
134145
logger.Info("msg", "verifying Mdm-Signature header", "err", err)
135146
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)

0 commit comments

Comments
 (0)