package.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /*
  2. * Copyright (c) 2015, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package psiphon
  20. import (
  21. "crypto"
  22. "crypto/rsa"
  23. "crypto/sha256"
  24. "crypto/x509"
  25. "encoding/base64"
  26. "encoding/json"
  27. "errors"
  28. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  29. )
  30. // AuthenticatedDataPackage is a JSON record containing some Psiphon data
  31. // payload, such as list of Psiphon server entries. As it may be downloaded
  32. // from various sources, it is digitally signed so that the data may be
  33. // authenticated.
  34. type AuthenticatedDataPackage struct {
  35. Data string `json:"data"`
  36. SigningPublicKeyDigest string `json:"signingPublicKeyDigest"`
  37. Signature string `json:"signature"`
  38. }
  39. func ReadAuthenticatedDataPackage(
  40. rawPackage []byte, signingPublicKey string) (data string, err error) {
  41. var authenticatedDataPackage *AuthenticatedDataPackage
  42. err = json.Unmarshal(rawPackage, &authenticatedDataPackage)
  43. if err != nil {
  44. return "", common.ContextError(err)
  45. }
  46. derEncodedPublicKey, err := base64.StdEncoding.DecodeString(signingPublicKey)
  47. if err != nil {
  48. return "", common.ContextError(err)
  49. }
  50. publicKey, err := x509.ParsePKIXPublicKey(derEncodedPublicKey)
  51. if err != nil {
  52. return "", common.ContextError(err)
  53. }
  54. rsaPublicKey, ok := publicKey.(*rsa.PublicKey)
  55. if !ok {
  56. return "", common.ContextError(errors.New("unexpected signing public key type"))
  57. }
  58. signature, err := base64.StdEncoding.DecodeString(authenticatedDataPackage.Signature)
  59. if err != nil {
  60. return "", common.ContextError(err)
  61. }
  62. // TODO: can distinguish signed-with-different-key from other errors:
  63. // match digest(publicKey) against authenticatedDataPackage.SigningPublicKeyDigest
  64. hash := sha256.New()
  65. hash.Write([]byte(authenticatedDataPackage.Data))
  66. digest := hash.Sum(nil)
  67. err = rsa.VerifyPKCS1v15(rsaPublicKey, crypto.SHA256, digest, signature)
  68. if err != nil {
  69. return "", common.ContextError(err)
  70. }
  71. return authenticatedDataPackage.Data, nil
  72. }