I want to be able to send iOS APNS push notifications using AWS SNS with the aws golang SDK. I've created a p12 file following this instructions: https://support-aws.s3.amazonaws.com/Exporting-APNS-Cert-Keychain-Mac.pdf now in order to get the private key and cert I need to implement the following openssl equivalent commands:
openssl pkcs12 -in MyCertificates.p12 -out MyCer.pem -clcerts -nokeys
openssl pkcs12 -in MyCertificates.p12 -out MyKey.pem -nocerts -nodes
openssl pkcs8 -topk8 -inform pem -in MyKey.pem -outform pem -nocrypt -out MyKeyCorrectFormat.pem
I can't find a way to do this in golang, any help will be appreciated. What seems to be the issue is converting the private key to pkcs8 format.
EDIT:
This is what I have been trying to do (in order to compile you need to change the first import in github.com/youmark/pkcs8 to golang.org/x/crypto/pbkdf2) :
import (
"golang.org/x/crypto/pkcs12"
"io/ioutil"
"fmt"
"encoding/pem"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"crypto/x509"
"crypto/rsa"
"errors"
"github.com/youmark/pkcs8"
)
func main() {
b, err:= ioutil.ReadFile("myP12File.p12")
if err!=nil {
fmt.Println(err)
return
}
password := "123456"
_, pKey , err := Decode(b,password)
pKeyPkcs8, err := pkcs8.ConvertPrivateKeyToPKCS8(pKey,passwordBytes)
if err!=nil {
fmt.Println(err)
}
fmt.Println(string(pKeyPkcs8))
}
// Decode and verify an in memory .p12 certificate (DER binary format).
func Decode(p12 []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
// decode an x509.Certificate to verify
privateKey, cert, err := pkcs12.Decode(p12, password)
if err != nil {
return nil, nil, err
}
if err := verify(cert); err != nil {
return nil, nil, err
}
// assert that private key is RSA
priv, ok := privateKey.(*rsa.PrivateKey)
if !ok {
return nil, nil, errors.New("expected RSA private key type")
}
return cert, priv, nil
}
// verify checks if a certificate has expired
func verify(cert *x509.Certificate) error {
_, err := cert.Verify(x509.VerifyOptions{})
if err == nil {
return nil
}
switch e := err.(type) {
case x509.CertificateInvalidError:
switch e.Reason {
case x509.Expired:
return ErrExpired
default:
return err
}
case x509.UnknownAuthorityError:
// Apple cert isn't in the cert pool
// ignoring this error
return nil
default:
return err
}
}
// Certificate errors
var (
ErrExpired = errors.New("certificate has expired or is not yet valid")
)
What I get when printing the converted key is gibberish, so I guess there is something wrong with my decoding process somewhere.