diff --git a/cmd/renew_apple_cert/README.md b/cmd/renew_apple_cert/README.md deleted file mode 100644 index 88f0e33..0000000 --- a/cmd/renew_apple_cert/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Utility for renewal or creation of apple push notification certificate -## Description -Automate steps for certificate creation or renewal for apple push notification service. - -### Rough description of tasks: -1. Create a Certificate Signing Request to upload via apple portal and get it signed -2. Download the certificate and convert it so it becomes usable by [mattermost-push-proxy](https://github.com/mattermost/mattermost-push-proxy) - -### Result: -2 scripts, 2 manual steps: -1. scripted creation of CSR via create_csr/main.go -2. manual upload of generated `certs/csr/*.csr` file -3. manual download of signed `aps.cer` file from apple portal -4. scripted extraction + conversion from `aps.cer` to `certs/converted/*_priv.pem` to be then usable for mattermost-push-proxy - -## Usage -### Prerequisites: -```bash -$ openssl version - OpenSSL 1.1.1f 31 Mar 2020 -``` - -### Steps -1. `$ cd cmd/renew_apple_cert/create_csr` -2. `$ cp config.sample.json config.json` -3. Fill in input information in `config/config.json` -4. `$ go run .` -5. Follow https://developers.mattermost.com/contribute/mobile/push-notifications/ios/ to upload the Certificate Signing Request *.csr generated by the script -6. Download the `aps.cer` from the apple portal and put it in `certs/downloaded/aps.cer`\ -7. `$ cd ../convert_cert` -8. `$ go run .` -9. Use `certs/converted/*_priv.pem` in the push proxy configuration as described [here](https://developers.mattermost.com/contribute/mobile/push-notifications/service/#set-up-mattermost-push-notification-service-to-send-ios-push-notifications) diff --git a/cmd/renew_apple_cert/convert_cert/config.go b/cmd/renew_apple_cert/convert_cert/config.go deleted file mode 100644 index 05ed783..0000000 --- a/cmd/renew_apple_cert/convert_cert/config.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package main - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/kelseyhightower/envconfig" -) - -type config struct { - App string - CertDir string - AppleGateway string -} - -func parseConfig(path string) (config, error) { - var cfg config - file, err := os.Open(path) - if err != nil { - return cfg, fmt.Errorf("could not open file: %w", err) - } - defer file.Close() - - err = json.NewDecoder(file).Decode(&cfg) - if err != nil { - return cfg, fmt.Errorf("could not decode file: %w", err) - } - - if err = envconfig.Process("convert_cert", &cfg); err != nil { - return cfg, err - } - - return cfg, nil -} diff --git a/cmd/renew_apple_cert/convert_cert/config.sample.json b/cmd/renew_apple_cert/convert_cert/config.sample.json deleted file mode 100644 index 6254f9d..0000000 --- a/cmd/renew_apple_cert/convert_cert/config.sample.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "App": "mattermost", - "CertDir": "../certs", - "AppleGateway": "gateway.push.apple.com:2195" -} \ No newline at end of file diff --git a/cmd/renew_apple_cert/convert_cert/main.go b/cmd/renew_apple_cert/convert_cert/main.go deleted file mode 100644 index f1b2794..0000000 --- a/cmd/renew_apple_cert/convert_cert/main.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package main - -import ( - "flag" - "fmt" - "log" - "os" - "os/exec" - "path" -) - -const ( - csrSubDir = "csr" - downloadedSubDir = "downloaded" - convertedSubDir = "converted" - - // Important files - apsP12 = "aps.p12" - apsPem = "aps.pem" - apsCer = "aps.cer" -) - -func main() { - var configFile string - flag.StringVar(&configFile, "config", "config/config.json", "Configuration file for convert_cert.") - flag.Parse() - - cfg, err := parseConfig(configFile) - if err != nil { - log.Fatal(err) - } - - err = createDirs(path.Join(cfg.CertDir, cfg.App)) - if err != nil { - log.Fatal(err.Error()) - } - - dirCSR := path.Join(cfg.CertDir, cfg.App, csrSubDir) - dirConverted := path.Join(cfg.CertDir, cfg.App, convertedSubDir) - dirDownloaded := path.Join(cfg.CertDir, cfg.App, downloadedSubDir) - - err = convertCerToPem(dirDownloaded, dirConverted) - if err != nil { - log.Fatal("convertCerToPem:", err.Error()) - } - - err = convertPemToP12(dirCSR, dirConverted, cfg.App) - if err != nil { - log.Fatal("convertPemToP12:", err.Error()) - } - - err = extractPrivateKey(dirConverted, cfg.App) - if err != nil { - log.Fatal("extractPrivateKey:", err.Error()) - } - - err = verify(dirConverted, cfg.App, cfg.AppleGateway) - if err != nil { - log.Fatal("verify:", err.Error()) - } -} - -func createDirs(dir string) error { - dirs := []string{ - path.Join(dir, csrSubDir), - path.Join(dir, convertedSubDir), - path.Join(dir, downloadedSubDir), - } - for _, dir := range dirs { - err := os.MkdirAll(dir, 0700) - if err != nil { - return err - } - } - return nil -} - -func convertCerToPem(dirDownloaded, dirConverted string) error { - // openssl x509 -inform=der -in=certs/mattermost/downloaded/aps.cer -outform=pem -out=certs/mattermost/converted/aps.pem - cmd := exec.Command("openssl", "x509", - "-inform=der", - "-in="+path.Join(dirDownloaded, apsCer), - "-outform=pem", - "-out="+path.Join(dirConverted, apsPem), - ) - err := execCommand(cmd) - if err != nil { - return err - } - return nil -} - -func convertPemToP12(dirCSR, dirConverted, app string) error { - // openssl pkcs12 -export -inkey=certs/mattermost/csr/mattermost.key -in=certs/mattermost/converted/aps.pem -out=certs/mattermost/converted/aps.p12 -clcerts -passout=pass: - cmd := exec.Command("openssl", "pkcs12", - "-export", - "-inkey="+path.Join(dirCSR, app+".key"), - "-in="+path.Join(dirConverted, apsPem), - "-out="+path.Join(dirConverted, apsP12), - "-clcerts", - "-passout=pass:", - ) - err := execCommand(cmd) - if err != nil { - return err - } - return nil -} - -func extractPrivateKey(dirConverted, app string) error { - // openssl pkcs12 -in=certs/mattermost/converted/aps.p12 -out=certs/mattermost/mattermost/converted/classic_priv.pem -nodes -clcerts -passin=pass: - cmd := exec.Command("openssl", "pkcs12", - "-in="+path.Join(dirConverted, apsP12), - "-out="+path.Join(dirConverted, app+"_priv.pem"), - "-nodes", - "-clcerts", - "-passin=pass:", - ) - err := execCommand(cmd) - if err != nil { - return err - } - return nil -} - -func verify(dirConverted, app, gateway string) error { - // openssl s_client -connect=gateway.push.apple.com:2195 -cert=certs/mattermost/mattermost/converted/aps.pem -key=certs/mattermost/mattermost/converted/classic_priv.pem - cmd := exec.Command("openssl", "s_client", - "-connect="+gateway, - "-cert="+path.Join(dirConverted, apsPem), - "-key="+path.Join(dirConverted, app+"_priv.pem"), - ) - err := execCommand(cmd) - if err != nil { - return err - } - return nil -} - -func execCommand(cmd *exec.Cmd) error { - buf, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("%s: %w", string(buf), err) - } - if len(buf) == 0 { - return nil - } - log.Printf("Result: %s\n", string(buf)) - return nil -} diff --git a/cmd/renew_apple_cert/convert_cert/testdata/config.json b/cmd/renew_apple_cert/convert_cert/testdata/config.json deleted file mode 100644 index a632bf4..0000000 --- a/cmd/renew_apple_cert/convert_cert/testdata/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "App": "mattermost", - "CertDir": "testdata/certs", - "AppleGateway": "gateway.push.apple.com:2195" -} diff --git a/cmd/renew_apple_cert/create_csr/config.go b/cmd/renew_apple_cert/create_csr/config.go deleted file mode 100644 index d678e36..0000000 --- a/cmd/renew_apple_cert/create_csr/config.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package main - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/kelseyhightower/envconfig" -) - -type config struct { - App string - ApplePushTopic string - Country string - Province string - Locality string - Organization string - Email string - CertDir string -} - -func parseConfig(path string) (config, error) { - var cfg config - file, err := os.Open(path) - if err != nil { - return cfg, fmt.Errorf("could not open file: %w", err) - } - defer file.Close() - - err = json.NewDecoder(file).Decode(&cfg) - if err != nil { - return cfg, fmt.Errorf("could not decode file: %w", err) - } - - if err = envconfig.Process("create_csr", &cfg); err != nil { - return cfg, err - } - - return cfg, nil -} diff --git a/cmd/renew_apple_cert/create_csr/config.sample.json b/cmd/renew_apple_cert/create_csr/config.sample.json deleted file mode 100644 index 3ebf573..0000000 --- a/cmd/renew_apple_cert/create_csr/config.sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "App": "mattermost", - "CertDir": "../certs", - "ApplePushTopic": "com.mattermost.Mattermost", - "Country": "US", - "Province": "California", - "Locality": "Palo Alto", - "Organization": "Mattermost, Inc.", - "Email": "email@example.com" -} \ No newline at end of file diff --git a/cmd/renew_apple_cert/create_csr/main.go b/cmd/renew_apple_cert/create_csr/main.go deleted file mode 100644 index 5ea0da8..0000000 --- a/cmd/renew_apple_cert/create_csr/main.go +++ /dev/null @@ -1,118 +0,0 @@ -package main - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "encoding/pem" - "flag" - "io/ioutil" - "log" - "os" - "path" -) - -const ( - csrSubDir = "csr" - downloadedSubDir = "downloaded" -) - -func main() { - var configFile string - flag.StringVar(&configFile, "config", "config/config.json", "Configuration file for create_csr.") - flag.Parse() - - runJob(configFile) -} - -// runJob is an externalized version of main to facilitate testing. -func runJob(configFile string) { - cfg, err := parseConfig(configFile) - if err != nil { - log.Fatal(err) - } - - err = createDirs(path.Join(cfg.CertDir, cfg.App)) - if err != nil { - log.Fatal(err) - } - - dirCSR := path.Join(cfg.CertDir, cfg.App, csrSubDir) - key, err := createAndWritePrivateKey(cfg.App, dirCSR) - if err != nil { - log.Fatal("createAndWritePrivateKey:", err) - } - - err = createAndWriteCSR(cfg, key, dirCSR) - if err != nil { - log.Fatal("createAndWriteCSR:", err) - } -} - -func createDirs(dir string) error { - dirs := []string{ - path.Join(dir, csrSubDir), - path.Join(dir, downloadedSubDir), - } - for _, dir := range dirs { - err := os.MkdirAll(dir, 0700) - if err != nil { - return err - } - } - return nil -} - -func createAndWritePrivateKey(app, dirCSR string) (*rsa.PrivateKey, error) { - key, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return nil, err - } - marshaledKey := x509.MarshalPKCS1PrivateKey(key) - pemPrivateKey := pem.EncodeToMemory( - &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: marshaledKey, - }, - ) - err = ioutil.WriteFile(path.Join(dirCSR, app+".key"), pemPrivateKey, 0664) - if err != nil { - return nil, err - } - return key, err -} - -func createAndWriteCSR(cfg config, key *rsa.PrivateKey, dirCSR string) error { - subj := pkix.Name{ - CommonName: cfg.ApplePushTopic, - Country: []string{cfg.Country}, - Province: []string{cfg.Province}, - Locality: []string{cfg.Locality}, - Organization: []string{cfg.Organization}, - ExtraNames: []pkix.AttributeTypeAndValue{ - { - Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, - Value: asn1.RawValue{ - Tag: asn1.TagIA5String, - Bytes: []byte(cfg.Email), - }, - }, - }, - } - template := x509.CertificateRequest{ - Subject: subj, - SignatureAlgorithm: x509.SHA256WithRSA, - } - csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, key) - if err != nil { - return err - } - cr := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}) - err = ioutil.WriteFile(path.Join(dirCSR, cfg.App+".csr"), cr, 0664) - if err != nil { - return err - } - return nil -} diff --git a/cmd/renew_apple_cert/create_csr/main_test.go b/cmd/renew_apple_cert/create_csr/main_test.go deleted file mode 100644 index a12db2e..0000000 --- a/cmd/renew_apple_cert/create_csr/main_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "os" - "path" - "testing" -) - -func TestCSRCreation(t *testing.T) { - defer os.RemoveAll(path.Join("testdata", "certs")) - runJob(path.Join("testdata", "config.json")) - if _, err := os.Stat(path.Join("testdata", "certs", "mattermost", "csr", "mattermost.key")); os.IsNotExist(err) { - t.Error(err) - } - - if _, err := os.Stat(path.Join("testdata", "certs", "mattermost", "csr", "mattermost.csr")); os.IsNotExist(err) { - t.Error(err) - } -} diff --git a/cmd/renew_apple_cert/create_csr/testdata/config.json b/cmd/renew_apple_cert/create_csr/testdata/config.json deleted file mode 100644 index ba422e1..0000000 --- a/cmd/renew_apple_cert/create_csr/testdata/config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "App": "mattermost", - "CertDir": "testdata/certs", - "ApplePushTopic": "com.mattermost.Mattermost", - "Country": "US", - "Province": "California", - "Locality": "Palo Alto", - "Organization": "Mattermost, Inc.", - "Email": "email@example.com" -} \ No newline at end of file