Skip to content

Commit

Permalink
Add tests for certauth package
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepeterson committed Nov 20, 2021
1 parent fbe081c commit 60d4fc8
Show file tree
Hide file tree
Showing 2 changed files with 256 additions and 0 deletions.
170 changes: 170 additions & 0 deletions service/certauth/certauth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package certauth

import (
"errors"
"io/ioutil"
"os"
"testing"

"github.com/micromdm/nanomdm/mdm"
"github.com/micromdm/nanomdm/storage/file"
)

func loadAuthMsg() (*mdm.Authenticate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/Authenticate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.Authenticate)
if !ok {
return nil, errors.New("not an Authenticate message")
}
return a, nil
}

func loadTokenMsg() (*mdm.TokenUpdate, error) {
b, err := ioutil.ReadFile("../../mdm/testdata/TokenUpdate.2.plist")
if err != nil {
return nil, err
}
r, err := mdm.DecodeCheckin(b)
if err != nil {
return nil, err
}
a, ok := r.(*mdm.TokenUpdate)
if !ok {
return nil, errors.New("not a TokenUpdate message")
}
return a, nil
}

func TestNilCertAuth(t *testing.T) {
auth, err := loadAuthMsg()
if err != nil {
t.Fatal(err)
}
certAuth := New(nil, nil)
if certAuth == nil {
t.Fatal("New returned nil")
}
err = certAuth.Authenticate(&mdm.Request{}, auth)
if err == nil {
t.Fatal("expected error, nil returned")
}
if !errors.Is(err, ErrMissingCert) {
t.Fatalf("wrong error: %v", err)
}
}

func TestCertAuth(t *testing.T) {
_, crt, err := SimpleSelfSignedRSAKeypair("TESTDEVICE", 1)
if err != nil {
t.Fatal(err)
}
storage, err := file.New("test-db")
if err != nil {
t.Fatal(err)
}
certAuth := New(&NopService{}, storage)
if certAuth == nil {
t.Fatal("New returned nil")
}
token, err := loadTokenMsg()
if err != nil {
t.Fatal(err)
}
// a non-Auth message without first Auth'ing the cert should
// generate an ErrNoCertAssoc.
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt}, token)
if err == nil {
t.Fatal("expected err; nil returned")
}
if !errors.Is(err, ErrNoCertAssoc) {
t.Fatalf("wrong error: %v", err)
}
// send another one to make sure we're not accidentally allowing
// retroactive
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt}, token)
if err == nil {
t.Fatal("expected err; nil returned")
}
if !errors.Is(err, ErrNoCertAssoc) {
t.Fatalf("wrong error: %v", err)
}
authMsg, err := loadAuthMsg()
if err != nil {
t.Fatal(err)
}
// let's actually associate our cert...
err = certAuth.Authenticate(&mdm.Request{Certificate: crt}, authMsg)
if err != nil {
t.Fatal(err)
}
// ... and try again.
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt}, token)
if err != nil {
t.Fatal(err)
}
_, crt2, err := SimpleSelfSignedRSAKeypair("TESTDEVICE", 2)
if err != nil {
t.Fatal(err)
}
// lets try and spoof our UDID using another certificate (bad!)
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt2}, token)
if err == nil {
t.Fatal("expected err; nil returned")
}
if !errors.Is(err, ErrNoCertAssoc) {
t.Fatalf("wrong error: %v", err)
}
os.RemoveAll("test-db")
}

func TestCertAuthRetro(t *testing.T) {
_, crt, err := SimpleSelfSignedRSAKeypair("TESTDEVICE", 1)
if err != nil {
t.Fatal(err)
}
storage, err := file.New("test-db")
if err != nil {
t.Fatal(err)
}
certAuth := New(&NopService{}, storage, WithAllowRetroactive())
if certAuth == nil {
t.Fatal("New returned nil")
}
token, err := loadTokenMsg()
if err != nil {
t.Fatal(err)
}
// usually a non-Auth message without first Auth'ing the cert would
// generate an ErrNoCertAssoc. instead this should allow us to
// register a cert.
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt}, token)
if err != nil {
t.Fatal(err)
}
// send another one to make sure we're still associated
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt}, token)
if err != nil {
t.Fatal(err)
}
_, crt2, err := SimpleSelfSignedRSAKeypair("TESTDEVICE", 2)
if err != nil {
t.Fatal(err)
}
// lets try and spoof our UDID using another certificate (bad!) to
// make sure we were properly setting retroactive association
err = certAuth.TokenUpdate(&mdm.Request{Certificate: crt2}, token)
if err == nil {
t.Fatal("expected err; nil returned")
}
if !errors.Is(err, ErrNoCertReuse) {
t.Fatalf("wrong error: %v", err)
}
os.RemoveAll("test-db")
}
86 changes: 86 additions & 0 deletions service/certauth/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package certauth

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"math/big"
"time"

"github.com/micromdm/nanomdm/mdm"
)

func GenerateRandomCertificateSerialNumber() (*big.Int, error) {
limit := new(big.Int).Lsh(big.NewInt(1), 128)
return rand.Int(rand.Reader, limit)
}

func SimpleSelfSignedRSAKeypair(cn string, days int) (key *rsa.PrivateKey, cert *x509.Certificate, err error) {
key, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return key, cert, err
}

serialNumber, err := GenerateRandomCertificateSerialNumber()
if err != nil {
return key, cert, err
}
timeNow := time.Now()
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: cn,
},
NotBefore: timeNow,
NotAfter: timeNow.Add(time.Duration(days) * 24 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
DNSNames: []string{cn},
}
certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
return key, cert, err
}
cert, err = x509.ParseCertificate(certBytes)
if err != nil {
return key, cert, err
}

return key, cert, err
}

type NopService struct{}

func (s *NopService) Authenticate(r *mdm.Request, m *mdm.Authenticate) error {
return nil
}

func (s *NopService) TokenUpdate(r *mdm.Request, m *mdm.TokenUpdate) error {
return nil
}

func (s *NopService) CheckOut(r *mdm.Request, m *mdm.CheckOut) error {
return nil
}

func (s *NopService) UserAuthenticate(r *mdm.Request, m *mdm.UserAuthenticate) ([]byte, error) {
return nil, nil
}

func (s *NopService) SetBootstrapToken(r *mdm.Request, m *mdm.SetBootstrapToken) error {
return nil
}

func (s *NopService) GetBootstrapToken(r *mdm.Request, m *mdm.GetBootstrapToken) (*mdm.BootstrapToken, error) {
return nil, nil
}

func (s *NopService) DeclarativeManagement(r *mdm.Request, m *mdm.DeclarativeManagement) ([]byte, error) {
return nil, nil
}

func (s *NopService) CommandAndReportResults(r *mdm.Request, results *mdm.CommandResults) (*mdm.Command, error) {
return nil, nil
}

0 comments on commit 60d4fc8

Please sign in to comment.