From 472d416791f9ef822a6601763b0a6ffbc7c4b022 Mon Sep 17 00:00:00 2001 From: Victor Vrantchan Date: Tue, 21 Mar 2017 20:22:04 -0400 Subject: [PATCH] decrypt private key if password provided For #101 --- CHANGELOG.md | 1 + serve.go | 26 ++++++++++++++++++++++---- serve_test.go | 31 +++++++++++++++++++++++++++++++ testdata/ProviderPrivateKey.key | 30 ++++++++++++++++++++++++++++++ testdata/pushcert.p12 | Bin 0 -> 2365 bytes testdata/pushcert.pem | 18 ++++++++++++++++++ 6 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 serve_test.go create mode 100644 testdata/ProviderPrivateKey.key create mode 100644 testdata/pushcert.p12 create mode 100644 testdata/pushcert.pem diff --git a/CHANGELOG.md b/CHANGELOG.md index dc636d57..0b1fc527 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # v1.0.1 TBD +* Decrypt armored private keys if the `-apns-password` flag is specified by the user. #105 * Improved command queue handling of NotNow and other responses. #96 * Fixed data race in pubsub package. #97 * Fixed bug that would cause PushInfo Token for the device to be replaced by one for the user. #90 diff --git a/serve.go b/serve.go index 1c7cacdb..c7abb3e7 100644 --- a/serve.go +++ b/serve.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "context" "crypto/rsa" "crypto/tls" @@ -55,8 +56,8 @@ func serve(args []string) error { flagset := flag.NewFlagSet("serve", flag.ExitOnError) var ( flServerURL = flagset.String("server-url", "", "public HTTPS url of your server") - flAPNSCertPath = flagset.String("apns-cert", "mdm.p12", "path to APNS certificate") - flAPNSKeyPass = flagset.String("apns-password", "secret", "password for your p12 APNS cert file (if using)") + flAPNSCertPath = flagset.String("apns-cert", "", "path to APNS certificate") + flAPNSKeyPass = flagset.String("apns-password", "", "password for your p12 APNS cert file (if using)") flAPNSKeyPath = flagset.String("apns-key", "", "path to key file if using .pem push cert") flTLS = flagset.Bool("tls", true, "use https") flTLSCert = flagset.String("tls-cert", "", "path to TLS certificate") @@ -395,13 +396,30 @@ func (c *config) loadPushCerts() { return } + pkeyBlock := new(bytes.Buffer) pemBlock, _ = pem.Decode(pemData) if pemBlock == nil { c.err = errors.New("invalid PEM data for privkey") return } - c.pushCert.PrivateKey, c.err = - x509.ParsePKCS1PrivateKey(pemBlock.Bytes) + + if x509.IsEncryptedPEMBlock(pemBlock) { + b, err := x509.DecryptPEMBlock(pemBlock, []byte(c.APNSPrivateKeyPass)) + if err != nil { + c.err = fmt.Errorf("decrypting DES private key %s", err) + return + } + pkeyBlock.Write(b) + } else { + pkeyBlock.Write(pemBlock.Bytes) + } + + priv, err := x509.ParsePKCS1PrivateKey(pkeyBlock.Bytes()) + if err != nil { + c.err = fmt.Errorf("parsing pkcs1 private key: %s", err) + return + } + c.pushCert.PrivateKey = priv } type pushServiceCert struct { diff --git a/serve_test.go b/serve_test.go new file mode 100644 index 00000000..4f3f5d05 --- /dev/null +++ b/serve_test.go @@ -0,0 +1,31 @@ +package main + +import "testing" + +func TestLoadPushCerts(t *testing.T) { + keypath := "testdata/ProviderPrivateKey.key" + certpath := "testdata/pushcert.pem" + p12path := "testdata/pushcert.p12" + keysecret := "secret" + + cfg := &config{ + APNSPrivateKeyPath: keypath, + APNSCertificatePath: certpath, + APNSPrivateKeyPass: keysecret, + } + + // test separate key and cert + cfg.loadPushCerts() + if cfg.err != nil { + t.Fatal(cfg.err) + } + + // test p12 with secret + cfg.APNSCertificatePath = p12path + cfg.APNSPrivateKeyPath = "" + cfg.loadPushCerts() + if cfg.err != nil { + t.Fatal(cfg.err) + } + +} diff --git a/testdata/ProviderPrivateKey.key b/testdata/ProviderPrivateKey.key new file mode 100644 index 00000000..647c64f8 --- /dev/null +++ b/testdata/ProviderPrivateKey.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,22c0f4c89c7b1fcd + +KVnJeaMzHPrL5pHmkB6yAR9N8cvh2FKBfmJuRP61GiSR+PAI1UxsZ+627cnNZc/8 +Y2haoxAtW4k5Yl6gIQH8exf4el5yD+Ds4mEUacw7m3RV+WNL32I1+Z+jr55jetzP +nb3t9LQmsP07uigSe/oh0vumVhjxxSE31/iB2BISnEfJDsDYHFFc1XWAxNABG+JP +ttCnIHPXaFLb7jDdZnnsk2rBNsRkOPwJ27hna9b0RyHVmqMb3XZtQs2RtARTVqap +hCFSphMrS20wLqcHyJZ7v0p9MiCp71g58xs4Bl9Vh1FI86AA+AOaosA0Kl8lPa08 +ChuJf7ng3mhJ+nKRkPUK4eDtnCsNm3Xd0lQQHqRWcoUJ80Gdhla0CodJnt/BT35y +SP+j2SUJRuAvNpSeGyAcLv3wDwhMgkVTt1errZOL0tFa/ep5YwfFPMBDVNXx+lOd +AHDey8gnoGJFpwoQFdXp6TVZEJjP6kgN8njmAZmbwrFcqMdjg+eMZfAYXUAdy4aT +aMbMGwjyjUgP80iXX5OAgGchpQ+HO5otpbecAMKs6SAqAgTMbKMG2rLgZe+mlkbd +6xnwyrhkQpQHVN97gqWic2cIggyR3UL58mned/5eS3EcNTTxHJO8D7EwmIjkGVxY +fT+tdpJ6iKK6CfjIEZYFgtLafmKMxxDHaplLGnIK8VHiopwUIKxVcji9Pjp+0a1O +q9NSVZXAbt45mL2jV94hhEpt83YyBFdRYBFk5LT7AQg2ipVl51g7fO2SoTiHakzL +MrKfo+bSxDHOWefu9Z380Vmh1Mm0xDU44C8g9Jc4N7euCQtGfX5bnWuueuGwaaXL +lYrqKVuqKdc2y5d8N7KiHEHY0zsfyjFu4+zh/v2zYIBlbuM9ZGiuSlprHvy//wev +kPZDEtHNTeFXBn7qDeTGNlYK+aGQyTFOzasXcUbf3RywjpHOM/uL7rUpA11W+Ip/ +/b1h+mcADy90DMBv1xVX3vZVldwAdcqbQR0QTXxgCS1dzVdedG2N7noJVKUfbA4x +tI3NEAaBt7J7eLQm7TawRv6j5G+VB/ZS5B8WVCVbBjwwqbeccJcuzJKLBX0A7c+X +TouVuE7xpq9OK0zsaIwg7WMgKOY9ZMuMNzjKnXcSYcq5o9LHHsB1CHyOGdHkmj/J +AmME2xnyB+GCLWyN8B17hyC4MwkoNDWLnlUzL1Z3lf5jsorx+zORKho+rgg02Blw +hY02jVEcHoO8fup6GXkWtWpq2pljHD6DBg4thqwd2X3tpKBEDCcPYjMNRBmb+EZo +ZZrHMZX999BsgQip+9s6gpg4OxLbkn/wB94D+XoQYCF/rKb3ztlMHWygyjasKbWe +L5DnI4tDaO0CAYP79ixJWd8DnHy7lkDFCWA3ZdDV5brM81biJVr24b0SoV22/nT/ +wvTP0wgdRBmBmqFYZojlIWM+Gu09tVqXy8ui5oOGJThXgCyPWPrs9PSIfLyOjfDm +vUy/3yhOfCZmLEFG955P3A92ygojs/EvIrE2oWKVxf0X+T0mIVnBxeWpQ0OOVC1q +51gz/pyLNjbqxP2FUOkF5hLvRupAHhFpzbP4yZcDHUisNyUgjb4kHQ== +-----END RSA PRIVATE KEY----- diff --git a/testdata/pushcert.p12 b/testdata/pushcert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c3cd1538b210533527bee750a2242dece5a3593b GIT binary patch literal 2365 zcmV-D3BvX;f(bbS0Ru3C2>%8NDuzgg_YDCD0ic2i@C1Sg>@b1|=rDo9kR>#?tL(O$5?xC|sC+Uil_1dRox2DNRVd0<-*goRTMNLB98oA4 z@ZJe3Mrdd=O)yw7Iw-n0In~)G5`!0kVS7xC*rV zAdQ!rm7uNS&*a24l=bgsHjSjcvfuE0h_^}ba^VZAGQ5fb#~hMG6@hwidv!%T0V7f> z+2T3hQO^`=N;k{RQK_EgoEy8bvJLMQatPZcWG%&B`cq&6>AlIRUZ>V7dofw-?3 zcEOV1Ez(g}noHn_Un6e2KcD1gvDl2uXG81Gd zFxXqzs)CdkcgQec)~Ozpnb;%a1#?+k{kXk+)Ks9Wl^%1Gl@_66tP4rwZqU?nt9!Yr z%qCr6vj54;EC6_<>1v)428qn>%-+$)=vAB*0-JHn!35mjhSVNFTyhOR28`p8xduhn z__^NFc-PNp`FuD&xV5BcoZf#tm~-ScIvDg?8T6Sy%N)2_?_T~^CEa^kgSutl14MG0 zd9cq$7c!?dz&=~_p@Is1rpO3}B5L~%Nl3LDnqjzQD+WF{K36-MZipZ)-reQe#!SR@dfsQ8s&#@A{-kBlurknfOD*bsD2g` z7@7q$P)boHL_64hAQe4ARpQQ+1^?JI6MRso+fP;AKYAcfDq)x%yjDWInb@*v5H;e_ zV)+UwuT1Dk$Z!|dW6j-cd!mwUaD1-W`}zRN1k$OLMz4o-QO}oI-+7h!6$V~2cJS}X zprsC7UNMr)$#HZ(pzNMWS!FnysJ_xPe7^0;4aOeMKW#;WD$eni1#3>8DdzYHRFoFd^1_>&LNQU;|O{5E@RD- z#@=Gn9j_eHD39tYWl?0pvJ-9?0>WUhMZrsXAHNKZMl_fTl!un(W|~0ous;DjFD+&9 z7EavMQW@dc&=uroXVS_{0YigtQ&LX3)GOV1NU^|trMj3PYd@WO z(BNc>KwPn^RBTA|`9*PNj;r^)`m2m3r^hNRi2(+!y+?Cxr_wLEBgD|=?2puPCJUB_ zFZ5t9I8z9#fR$W_hO~G-ii_#{<-2V}?NJJ%SxFECIBP6Y39g0r= z)c=kU5K82~(UqEYzeBK|Hl;IIhc$p@x*@JNDGrrf139wwnAh?-oHH-dWaz{`)gWQh zJq%NhdauDn35JeU!7~IUDDQQ#>k}n6T4$JCEoLDP=o#d_@M;%-9!7s+c)q?X$b>F$ zl(F%ommk_{hWITbp|iVr?*AZe;0&6e=o+or5{M_|j}ClMnI`9J=iTdx2Vx$^kK6X- z=iB;k3gLMVIM1q%e8n5_&x=FPzcpk%SDkY)H zXz~I=k!CQ^X~KD?>-WpGX93fP*O%_PhU+ZUDlMA5w<1ePeQ!n;f3FZ!nbiG}#kVh* z6vm=x?`r$iT3E&nb_%sigE{iB^CDq6X$EeRCg?pJwfc+s2eQ@XWGaKT$jf9a*z@kW zB$b-t65RZxmu!=DA=}wa3>0Le`51@Pg&%Rz`;r@Ef~$J98EcRM#OT7uo>9(yP70x^ z?cgqjBMPE}6YWy*sa!hRsbodVQu5d2z$70N@8d1*4wf&!vJqV~)ma*ytUI=HD9@MT z=a3bt%J7~Yu)JdQ%JtoH=fjdix*Y`5Re_Qx?|LyXAQLh&Ub7J8$&`2`=bV6KyTF6r zgts*P2Em(g$AxjTm2%ivQ?~<^=}F&3z=*f$)3F8b8LVu^T^b-4BKLs~9}O^kH0EczJ) zMNAUPn{93%?(}3Ie~!K2)@7VOZ*YO5HHc)TP$e97e^e zscV*0w%6n2qg&?d%M4k`sNeNi8%sJMc8dO4bMSoGu})7V&QtGd7RzDTFUv69cSz^8 z)DMOQ4-aD}UHO%q#-YUB9C8?GMXE)x*x~xlr}OTjx9J+{M=M%*KRH;=B=^3{{!-z%Vf|AutIB1uG5%0vZJX1Qe_; j9aC~EBY;$Ur`~~t(#ir)axw%69_>Xs1|c4o0s;sCDr#N4 literal 0 HcmV?d00001 diff --git a/testdata/pushcert.pem b/testdata/pushcert.pem new file mode 100644 index 00000000..1328e203 --- /dev/null +++ b/testdata/pushcert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9zCCAd+gAwIBAgIJAPQybPTtooGmMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV +BAMMB21kbXB1c2gwHhcNMTcwMzIxMjMyNzEwWhcNNDQwODA2MjMyNzEwWjASMRAw +DgYDVQQDDAdtZG1wdXNoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +43VCT3Xw62hJ1t3HhLNsyJ/wTTaLJfyNu9zwNeNVY+yOxSaj6V5UVEpWiNIfyB+j +J7E+cUdWmEQewwXPaoNsCR4bKBElB1f45UApcrmkoqzruFI4O+yfmLJkN95fO5Sd +009VZPudFf96HdYjNpgg8ofIxAxo9dP+ReU+4QgxevIM2Hg+X+4zabDiLspfGX6Y +A5Iz/R6rFCx8rc+GEWFhkB4JE0cIV/TifP5xlOr0UFTCYQ1KUEM+30s928PFRXM4 +tsm/TcM5g0Mi2bNDiVHE0hvzxmJbiL2XjFE3VBK6Dphw9gF1GLe8D2TnZMeIAj3K +JW0sjnkmvBxRvTqTHA4LvwIDAQABo1AwTjAdBgNVHQ4EFgQUJmri9d+KEYhPyDu3 +dHsVm7eFWngwHwYDVR0jBBgwFoAUJmri9d+KEYhPyDu3dHsVm7eFWngwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAmRu4hFq4+WN7Vr9FucU+yHYcj0YV +kKfJMUSxDK/bab1DR02gxcYVR+bY/xtlcc/dA0zzzXUj97/BKLpkQCxu1+MtqMPx +bbVJnrSkGDXBXMmwn9C29WDdMjLQwS4WLrkDTEVc8W9kUqZsEBQalneKlV8u5kXi +A9tolc2Kaq2uJxKcsC2Yx1MLqpEm6bqKRlQSPM0G3uWupJBnvIQfXt0n3ErphQhf +m6BuVIs2iVvEo2W+VZ+LwfeN992Yd0DeMqvMAh6Rg/N/SGaxmMeD/Co+LHKCAzW4 +JVjDjF01dBDmWTBs+NC9euIoCBej+PjMwXUo229uA19DucZXMIed9Xyoqg== +-----END CERTIFICATE-----