mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-12 04:55:39 +08:00
@@ -1,6 +1,9 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
@@ -91,19 +94,38 @@ pyQPbp8orlXe+tA8JA==
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
// VerifyFromAppleDeviceCA verifies a certificate was signed by Apple's iPhone Device CA.
|
||||
// TODO: We want to have more intensive verification (like the whole provided chain).
|
||||
// TODO: Implement some sort of cache so we don't need to parse PEM & DER every invocation.
|
||||
func VerifyFromAppleDeviceCA(c *x509.Certificate) error {
|
||||
func mustParsePublicKey(cert string) *rsa.PublicKey {
|
||||
block, _ := pem.Decode([]byte(appleiPhoneDeviceCAPEM))
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
panic("appleiPhoneDeviceCAPEM: invalid PEM block")
|
||||
}
|
||||
parent, err := x509.ParseCertificate(block.Bytes)
|
||||
c, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("appleiPhoneDeviceCAPEM: err parsing: %s", err))
|
||||
panic(fmt.Sprintf("appleiPhoneDeviceCAPEM: err parsing: %v", err))
|
||||
}
|
||||
// Note we CheckSignatureFrom() as we cannot Verify the certificate chain
|
||||
// (known expired intermediate)
|
||||
return c.CheckSignatureFrom(parent)
|
||||
|
||||
key, ok := c.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
panic("appleiPhoneDeviceCAPEM: invalid key type")
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
// extract public key from appleiPhoneDeviceCAPEM
|
||||
var appleiPhoneDeviceCAPublicKey = mustParsePublicKey(appleiPhoneDeviceCAPEM)
|
||||
|
||||
// VerifyFromAppleDeviceCA verifies a certificate was signed by Apple's iPhone Device CA.
|
||||
// Manually verify the certificate since Go has deprecated verifying SHA1WithRSA x509 certificates.
|
||||
func VerifyFromAppleDeviceCA(c *x509.Certificate) error {
|
||||
if c.SignatureAlgorithm != x509.SHA1WithRSA {
|
||||
return x509.ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
hashed := sha1.Sum(c.RawTBSCertificate)
|
||||
if err := rsa.VerifyPKCS1v15(appleiPhoneDeviceCAPublicKey, crypto.SHA1, hashed[:], c.Signature); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
46
pkg/crypto/apple_test.go
Normal file
46
pkg/crypto/apple_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCmpAppleDeviceCAPublicKey(t *testing.T) {
|
||||
block, _ := pem.Decode([]byte(appleiPhoneDeviceCAPEM))
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
t.Fatalf("appleiPhoneDeviceCAPEM: invalid PEM block")
|
||||
}
|
||||
parent, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("appleiPhoneDeviceCAPEM: err parsing: %v", err)
|
||||
}
|
||||
|
||||
if !appleiPhoneDeviceCAPublicKey.Equal(parent.PublicKey) {
|
||||
t.Error("appleiPhoneDeviceCAPEM: public keys not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyFromAppleDeviceCA(t *testing.T) {
|
||||
// extracted from /Library/Keychains/apsd.keychain
|
||||
cert, _ := ReadPEMCertificateFile("testdata/appleca_signed.pem")
|
||||
|
||||
if err := VerifyFromAppleDeviceCA(cert); err != nil {
|
||||
t.Errorf("received error verifying Apple Device CA: %v", err)
|
||||
}
|
||||
|
||||
// test invalidly-signed cert
|
||||
// reuse cert so we don't need to generate one. This should fail since it's not self-signed.
|
||||
block, _ := pem.Decode([]byte(appleiPhoneDeviceCAPEM))
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
t.Fatalf("appleiPhoneDeviceCAPEM: invalid PEM block")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("appleiPhoneDeviceCAPEM: err parsing: %v", err)
|
||||
}
|
||||
|
||||
if err := VerifyFromAppleDeviceCA(cert); err == nil {
|
||||
t.Error("expected error verifying non-apple-device-signed cert")
|
||||
}
|
||||
}
|
||||
17
pkg/crypto/testdata/appleca_signed.pem
vendored
Normal file
17
pkg/crypto/testdata/appleca_signed.pem
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICnjCCAgegAwIBAgIKATVAHcKbZdw3hDANBgkqhkiG9w0BAQUFADBaMQswCQYD
|
||||
VQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEVMBMGA1UECxMMQXBwbGUgaVBo
|
||||
b25lMR8wHQYDVQQDExZBcHBsZSBpUGhvbmUgRGV2aWNlIENBMB4XDTE4MTEwODE0
|
||||
MzYzNloXDTE5MTEwODE0NDEzNlowLzEtMCsGA1UEAxYkNjAwMUE5NTctNkZDNS00
|
||||
ODU2LThDNUUtREMyRTMyQzYxQ0I5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||
gQDhOLz0DpG1DmYqtLl/qsMDNDg9EI4MwC2XiHTq2kixj7otzqQYvIxwjm1ou31p
|
||||
QIfyqVgpKRKEBiHtWQS5lD77yTJqch5X0zuOF1rw8+s2NXxbQaGXh2YstwhySoLd
|
||||
679t6Zn4ftlkpkB5qO427i2nCiJ8TpJ+bwQQCOgDYoomaQIDAQABo4GVMIGSMB8G
|
||||
A1UdIwQYMBaAFLL+ISNEhpVqedWBJo5zENinTI50MB0GA1UdDgQWBBS1DsHPDXar
|
||||
x0iuOBXnfPZeHU3CYjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDAgBgNV
|
||||
HSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEAYKKoZIhvdjZAYKBAQCBQAw
|
||||
DQYJKoZIhvcNAQEFBQADgYEAx9vvPrfMBQaPJirj7cGK9Bp0bNhcmZ9iOOn4Y0kK
|
||||
3ygbclt2lPhB+wl+rMTPo0qky/JsCN9G2YvyEwOXYpJEOz+UNYGIXrfGW4pFJFR+
|
||||
pVroqXfkAqUgg2ipZwaR7fWugPakRjrD5SDLHH43y1bch3+Zy1Rg0RI3RrUa12Th
|
||||
uHM=
|
||||
-----END CERTIFICATE-----
|
||||
Reference in New Issue
Block a user