Commit f3af392d authored by Sybren A. Stüvel's avatar Sybren A. Stüvel

Gracefully handle case when server public key is not known

parent f29021c9
......@@ -82,16 +82,22 @@ func LoadCredentials() Credentials {
}
logger.WithField("url", creds.apiURL.String()).Debug("set API URL based on API mode")
if creds.ServerPublicKey != "" {
creds.serverPublicKey = parsePublicRSAKeyString(creds.ServerPublicKey)
}
creds.updateServerPublicKey()
return creds
}
func (creds *Credentials) updateServerPublicKey() {
if creds.ServerPublicKey == "" {
creds.serverPublicKey = nil
} else {
creds.serverPublicKey = parsePublicRSAKeyString(creds.ServerPublicKey)
}
}
// Endpoint returns the URL for a given endpoint name.
// It takes sandbox/production switching into account.
func (creds Credentials) Endpoint(endpoint string) string {
func (creds *Credentials) Endpoint(endpoint string) string {
endpointURL, err := creds.apiURL.Parse(endpoint)
if err != nil {
log.WithFields(logrus.Fields{
......@@ -105,7 +111,7 @@ func (creds Credentials) Endpoint(endpoint string) string {
}
// Save stores the credentials in the same file they were read from.
func (creds Credentials) Save() {
func (creds *Credentials) Save() {
logger := log.WithField("filename", creds.filename)
bytes, err := yaml.Marshal(creds)
......
......@@ -79,7 +79,7 @@ func (c *Client) newRequest(method, endpoint string, payload interface{}) *http.
logrus.ErrorKey: err,
}).Panic("unable to marshal payload as JSON")
}
fmt.Printf("\n%s\n\n", string(body))
// fmt.Printf("\n%s\n\n", string(body))
}
req, err := http.NewRequest(method, url, bytes.NewReader(body))
......@@ -126,7 +126,15 @@ func (c *Client) DoRequest(method, endpoint string, payload interface{}, respons
logger.WithError(err).Fatal("unable to perform HTTP call")
}
c.VerifyResponse(resp)
// We can only verify the response when we have an RSA key, and we get that through the 'installation' call.
switch endpoint {
case "installation":
logger.Debug("accepting server response without ability to verify")
default:
if err := c.VerifyResponse(resp); err != nil {
logger.WithError(err).Fatal("unable to verify server response")
}
}
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
......
......@@ -93,6 +93,7 @@ func (c *Client) PostInstallation() {
c.creds.ServerPublicKey = response.ServerPublicKey.Key
c.creds.InstallationToken = response.Token.Token
c.creds.updateServerPublicKey()
log.WithFields(logrus.Fields{
"installationToken": c.creds.InstallationToken,
......
......@@ -29,6 +29,7 @@ import (
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"net/http"
......@@ -37,6 +38,9 @@ import (
"strings"
)
// ErrNoServerKey is returned when trying to verify a response without the server's RSA key.
var ErrNoServerKey = errors.New("server public RSA key not available")
// The headers to include in the signature. "X-Bunq-..." headers are always included.
var headersToSign = map[string]bool{
headerCacheControl: true,
......@@ -111,6 +115,10 @@ func (c *Client) SignRequest(r *http.Request) error {
// VerifyResponse verifies a HTTP response using the server's public RSA key.
// We obtained the server's key in the PostInstall() function.
func (c *Client) VerifyResponse(r *http.Response) error {
if c.creds.serverPublicKey == nil {
return ErrNoServerKey
}
// TODO: merge common code between this function and SignRequest().
serverSignatureB64 := r.Header.Get(headerXBunqServerSignature)
if serverSignatureB64 == "" {
......@@ -146,10 +154,9 @@ func (c *Client) VerifyResponse(r *http.Response) error {
// log.WithField("value", string(bodyBytes)).Debug("writing body to hasher")
r.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
sum := hasher.Sum(nil)
// Verify the signature just to be sure ;-)
// Verify the signature.
serverSignature, err := base64.StdEncoding.DecodeString(serverSignatureB64)
if err != nil {
log.WithError(err).Fatal("unable to base64-decode the server signature")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment