feat(pki): add trust store wrapper and iOS mobileconfig generation
- commit
- 1c010968359878613bacf019f676403ce064091a
- author
- brice · · 2026-03-29 16:41 UTC
- parent
- b939cf1
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
5 files · +111 -0
M go.mod +2 -0
| @@ -15,6 +15,7 @@ require ( | |||
| 15 | 15 | github.com/mattn/go-runewidth v0.0.21 | |
| 16 | 16 | github.com/muesli/termenv v0.16.0 | |
| 17 | 17 | github.com/rivo/uniseg v0.4.7 | |
| 18 | + | github.com/smallstep/truststore v0.13.0 | |
| 18 | 19 | github.com/spf13/cobra v1.10.2 | |
| 19 | 20 | github.com/spf13/viper v1.21.0 | |
| 20 | 21 | github.com/stretchr/testify v1.11.1 | |
| @@ -67,6 +68,7 @@ require ( | |||
| 67 | 68 | google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect | |
| 68 | 69 | google.golang.org/grpc v1.79.3 // indirect | |
| 69 | 70 | google.golang.org/protobuf v1.36.11 // indirect | |
| 71 | + | howett.net/plist v1.0.0 // indirect | |
| 70 | 72 | ) | |
| 71 | 73 | ||
| 72 | 74 | require ( | |
| @@ -15,6 +15,7 @@ require ( | |||||
| 15 | github.com/mattn/go-runewidth v0.0.21 | 15 | github.com/mattn/go-runewidth v0.0.21 | ||
| 16 | github.com/muesli/termenv v0.16.0 | 16 | github.com/muesli/termenv v0.16.0 | ||
| 17 | github.com/rivo/uniseg v0.4.7 | 17 | github.com/rivo/uniseg v0.4.7 | ||
| 18 | + | github.com/smallstep/truststore v0.13.0 | |||
| 18 | github.com/spf13/cobra v1.10.2 | 19 | github.com/spf13/cobra v1.10.2 | ||
| 19 | github.com/spf13/viper v1.21.0 | 20 | github.com/spf13/viper v1.21.0 | ||
| 20 | github.com/stretchr/testify v1.11.1 | 21 | github.com/stretchr/testify v1.11.1 | ||
| @@ -67,6 +68,7 @@ require ( | |||||
| 67 | google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect | 68 | google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect | ||
| 68 | google.golang.org/grpc v1.79.3 // indirect | 69 | google.golang.org/grpc v1.79.3 // indirect | ||
| 69 | google.golang.org/protobuf v1.36.11 // indirect | 70 | google.golang.org/protobuf v1.36.11 // indirect | ||
| 71 | + | howett.net/plist v1.0.0 // indirect | |||
| 70 | ) | 72 | ) | ||
| 71 | 73 | ||||
| 72 | require ( | 74 | require ( | ||
M go.sum +6 -0
| @@ -92,6 +92,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz | |||
| 92 | 92 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= | |
| 93 | 93 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | |
| 94 | 94 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | |
| 95 | + | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | |
| 95 | 96 | github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= | |
| 96 | 97 | github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= | |
| 97 | 98 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | |
| @@ -151,6 +152,8 @@ github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88ee | |||
| 151 | 152 | github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= | |
| 152 | 153 | github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= | |
| 153 | 154 | github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= | |
| 155 | + | github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4= | |
| 156 | + | github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A= | |
| 154 | 157 | github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= | |
| 155 | 158 | github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= | |
| 156 | 159 | github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= | |
| @@ -241,7 +244,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN | |||
| 241 | 244 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | |
| 242 | 245 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= | |
| 243 | 246 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= | |
| 247 | + | gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= | |
| 244 | 248 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |
| 245 | 249 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
| 246 | 250 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= | |
| 247 | 251 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= | |
| 252 | + | howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= | |
| 253 | + | howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= | |
| @@ -92,6 +92,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz | |||||
| 92 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= | 92 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= | ||
| 93 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | 93 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | ||
| 94 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | 94 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
| 95 | + | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | |||
| 95 | github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= | 96 | github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= | ||
| 96 | github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= | 97 | github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= | ||
| 97 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | 98 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||
| @@ -151,6 +152,8 @@ github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88ee | |||||
| 151 | github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= | 152 | github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= | ||
| 152 | github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= | 153 | github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= | ||
| 153 | github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= | 154 | github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= | ||
| 155 | + | github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4= | |||
| 156 | + | github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A= | |||
| 154 | github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= | 157 | github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= | ||
| 155 | github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= | 158 | github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= | ||
| 156 | github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= | 159 | github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= | ||
| @@ -241,7 +244,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN | |||||
| 241 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | 244 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||
| 242 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= | 245 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= | ||
| 243 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= | 246 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= | ||
| 247 | + | gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= | |||
| 244 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | 248 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
| 245 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | 249 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
| 246 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= | 250 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= | ||
| 247 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= | 251 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= | ||
| 252 | + | howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= | |||
| 253 | + | howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= | |||
A internal/adapters/out/pki/mobileconfig.go +58 -0
| @@ -0,0 +1,58 @@ | |||
| 1 | + | package pki | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "encoding/base64" | |
| 5 | + | "fmt" | |
| 6 | + | ||
| 7 | + | "github.com/google/uuid" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | // GenerateMobileconfig generates an iOS configuration profile containing | |
| 11 | + | // the root CA certificate for one-tap trust installation. | |
| 12 | + | func GenerateMobileconfig(rootDER []byte, rootCN string) []byte { | |
| 13 | + | b64Cert := base64.StdEncoding.EncodeToString(rootDER) | |
| 14 | + | profileUUID := uuid.New().String() | |
| 15 | + | certUUID := uuid.New().String() | |
| 16 | + | ||
| 17 | + | profile := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> | |
| 18 | + | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 19 | + | <plist version="1.0"> | |
| 20 | + | <dict> | |
| 21 | + | <key>PayloadContent</key> | |
| 22 | + | <array> | |
| 23 | + | <dict> | |
| 24 | + | <key>PayloadCertificateFileName</key> | |
| 25 | + | <string>gordon-ca.crt</string> | |
| 26 | + | <key>PayloadContent</key> | |
| 27 | + | <data>%s</data> | |
| 28 | + | <key>PayloadDescription</key> | |
| 29 | + | <string>Installs the Gordon internal CA root certificate</string> | |
| 30 | + | <key>PayloadDisplayName</key> | |
| 31 | + | <string>%s</string> | |
| 32 | + | <key>PayloadIdentifier</key> | |
| 33 | + | <string>dev.gordon.ca.%s</string> | |
| 34 | + | <key>PayloadType</key> | |
| 35 | + | <string>com.apple.security.root</string> | |
| 36 | + | <key>PayloadUUID</key> | |
| 37 | + | <string>%s</string> | |
| 38 | + | <key>PayloadVersion</key> | |
| 39 | + | <integer>1</integer> | |
| 40 | + | </dict> | |
| 41 | + | </array> | |
| 42 | + | <key>PayloadDescription</key> | |
| 43 | + | <string>Trust Gordon's internal Certificate Authority for HTTPS access</string> | |
| 44 | + | <key>PayloadDisplayName</key> | |
| 45 | + | <string>Gordon CA Trust</string> | |
| 46 | + | <key>PayloadIdentifier</key> | |
| 47 | + | <string>dev.gordon.ca-profile</string> | |
| 48 | + | <key>PayloadType</key> | |
| 49 | + | <string>Configuration</string> | |
| 50 | + | <key>PayloadUUID</key> | |
| 51 | + | <string>%s</string> | |
| 52 | + | <key>PayloadVersion</key> | |
| 53 | + | <integer>1</integer> | |
| 54 | + | </dict> | |
| 55 | + | </plist>`, b64Cert, rootCN, certUUID, certUUID, profileUUID) | |
| 56 | + | ||
| 57 | + | return []byte(profile) | |
| 58 | + | } | |
| @@ -0,0 +1,58 @@ | |||||
| 1 | + | package pki | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "encoding/base64" | |||
| 5 | + | "fmt" | |||
| 6 | + | ||||
| 7 | + | "github.com/google/uuid" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | // GenerateMobileconfig generates an iOS configuration profile containing | |||
| 11 | + | // the root CA certificate for one-tap trust installation. | |||
| 12 | + | func GenerateMobileconfig(rootDER []byte, rootCN string) []byte { | |||
| 13 | + | b64Cert := base64.StdEncoding.EncodeToString(rootDER) | |||
| 14 | + | profileUUID := uuid.New().String() | |||
| 15 | + | certUUID := uuid.New().String() | |||
| 16 | + | ||||
| 17 | + | profile := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> | |||
| 18 | + | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| 19 | + | <plist version="1.0"> | |||
| 20 | + | <dict> | |||
| 21 | + | <key>PayloadContent</key> | |||
| 22 | + | <array> | |||
| 23 | + | <dict> | |||
| 24 | + | <key>PayloadCertificateFileName</key> | |||
| 25 | + | <string>gordon-ca.crt</string> | |||
| 26 | + | <key>PayloadContent</key> | |||
| 27 | + | <data>%s</data> | |||
| 28 | + | <key>PayloadDescription</key> | |||
| 29 | + | <string>Installs the Gordon internal CA root certificate</string> | |||
| 30 | + | <key>PayloadDisplayName</key> | |||
| 31 | + | <string>%s</string> | |||
| 32 | + | <key>PayloadIdentifier</key> | |||
| 33 | + | <string>dev.gordon.ca.%s</string> | |||
| 34 | + | <key>PayloadType</key> | |||
| 35 | + | <string>com.apple.security.root</string> | |||
| 36 | + | <key>PayloadUUID</key> | |||
| 37 | + | <string>%s</string> | |||
| 38 | + | <key>PayloadVersion</key> | |||
| 39 | + | <integer>1</integer> | |||
| 40 | + | </dict> | |||
| 41 | + | </array> | |||
| 42 | + | <key>PayloadDescription</key> | |||
| 43 | + | <string>Trust Gordon's internal Certificate Authority for HTTPS access</string> | |||
| 44 | + | <key>PayloadDisplayName</key> | |||
| 45 | + | <string>Gordon CA Trust</string> | |||
| 46 | + | <key>PayloadIdentifier</key> | |||
| 47 | + | <string>dev.gordon.ca-profile</string> | |||
| 48 | + | <key>PayloadType</key> | |||
| 49 | + | <string>Configuration</string> | |||
| 50 | + | <key>PayloadUUID</key> | |||
| 51 | + | <string>%s</string> | |||
| 52 | + | <key>PayloadVersion</key> | |||
| 53 | + | <integer>1</integer> | |||
| 54 | + | </dict> | |||
| 55 | + | </plist>`, b64Cert, rootCN, certUUID, certUUID, profileUUID) | |||
| 56 | + | ||||
| 57 | + | return []byte(profile) | |||
| 58 | + | } | |||
A internal/adapters/out/pki/mobileconfig_test.go +22 -0
| @@ -0,0 +1,22 @@ | |||
| 1 | + | package pki_test | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "strings" | |
| 5 | + | "testing" | |
| 6 | + | ||
| 7 | + | "github.com/bnema/gordon/internal/adapters/out/pki" | |
| 8 | + | "github.com/stretchr/testify/assert" | |
| 9 | + | "github.com/stretchr/testify/require" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | func TestGenerateMobileconfig(t *testing.T) { | |
| 13 | + | dir := t.TempDir() | |
| 14 | + | ca, err := pki.NewCA(dir, testLogger()) | |
| 15 | + | require.NoError(t, err) | |
| 16 | + | ||
| 17 | + | mc := pki.GenerateMobileconfig(ca.RootCertificateDER(), ca.RootCommonName()) | |
| 18 | + | assert.True(t, strings.HasPrefix(string(mc), "<?xml")) | |
| 19 | + | assert.Contains(t, string(mc), "Gordon Internal CA") | |
| 20 | + | assert.Contains(t, string(mc), "<key>PayloadType</key>") | |
| 21 | + | assert.Contains(t, string(mc), "com.apple.security.root") | |
| 22 | + | } | |
| @@ -0,0 +1,22 @@ | |||||
| 1 | + | package pki_test | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "strings" | |||
| 5 | + | "testing" | |||
| 6 | + | ||||
| 7 | + | "github.com/bnema/gordon/internal/adapters/out/pki" | |||
| 8 | + | "github.com/stretchr/testify/assert" | |||
| 9 | + | "github.com/stretchr/testify/require" | |||
| 10 | + | ) | |||
| 11 | + | ||||
| 12 | + | func TestGenerateMobileconfig(t *testing.T) { | |||
| 13 | + | dir := t.TempDir() | |||
| 14 | + | ca, err := pki.NewCA(dir, testLogger()) | |||
| 15 | + | require.NoError(t, err) | |||
| 16 | + | ||||
| 17 | + | mc := pki.GenerateMobileconfig(ca.RootCertificateDER(), ca.RootCommonName()) | |||
| 18 | + | assert.True(t, strings.HasPrefix(string(mc), "<?xml")) | |||
| 19 | + | assert.Contains(t, string(mc), "Gordon Internal CA") | |||
| 20 | + | assert.Contains(t, string(mc), "<key>PayloadType</key>") | |||
| 21 | + | assert.Contains(t, string(mc), "com.apple.security.root") | |||
| 22 | + | } | |||
A internal/adapters/out/pki/trust.go +23 -0
| @@ -0,0 +1,23 @@ | |||
| 1 | + | package pki | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "crypto/x509" | |
| 5 | + | ||
| 6 | + | "github.com/smallstep/truststore" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | // InstallRoot installs the root CA certificate into the system trust store. | |
| 10 | + | func InstallRoot(cert *x509.Certificate) error { | |
| 11 | + | return truststore.Install(cert, | |
| 12 | + | truststore.WithFirefox(), | |
| 13 | + | truststore.WithJava(), | |
| 14 | + | ) | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | // UninstallRoot removes the root CA certificate from the system trust store. | |
| 18 | + | func UninstallRoot(cert *x509.Certificate) error { | |
| 19 | + | return truststore.Uninstall(cert, | |
| 20 | + | truststore.WithFirefox(), | |
| 21 | + | truststore.WithJava(), | |
| 22 | + | ) | |
| 23 | + | } | |
| @@ -0,0 +1,23 @@ | |||||
| 1 | + | package pki | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "crypto/x509" | |||
| 5 | + | ||||
| 6 | + | "github.com/smallstep/truststore" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | // InstallRoot installs the root CA certificate into the system trust store. | |||
| 10 | + | func InstallRoot(cert *x509.Certificate) error { | |||
| 11 | + | return truststore.Install(cert, | |||
| 12 | + | truststore.WithFirefox(), | |||
| 13 | + | truststore.WithJava(), | |||
| 14 | + | ) | |||
| 15 | + | } | |||
| 16 | + | ||||
| 17 | + | // UninstallRoot removes the root CA certificate from the system trust store. | |||
| 18 | + | func UninstallRoot(cert *x509.Certificate) error { | |||
| 19 | + | return truststore.Uninstall(cert, | |||
| 20 | + | truststore.WithFirefox(), | |||
| 21 | + | truststore.WithJava(), | |||
| 22 | + | ) | |||
| 23 | + | } | |||