local-server/vendor/github.com/google/certificate-transparency-go/x509util/files.go
2018-07-03 18:32:39 +11:00

116 lines
3.5 KiB
Go

// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package x509util
import (
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"github.com/google/certificate-transparency-go/x509"
)
// ReadPossiblePEMFile loads data from a file which may be in DER format
// or may be in PEM format (with the given blockname).
func ReadPossiblePEMFile(filename, blockname string) ([][]byte, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("%s: failed to read data: %v", filename, err)
}
return dePEM(data, blockname), nil
}
// ReadPossiblePEMURL attempts to determine if the given target is a local file or a
// URL, and return the file contents regardless. It also copes with either PEM or DER
// format data.
func ReadPossiblePEMURL(target, blockname string) ([][]byte, error) {
if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
// Assume it's a filename
return ReadPossiblePEMFile(target, blockname)
}
rsp, err := http.Get(target)
if err != nil {
return nil, fmt.Errorf("failed to http.Get(%q): %v", target, err)
}
data, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return nil, fmt.Errorf("failed to ioutil.ReadAll(%q): %v", target, err)
}
return dePEM(data, blockname), nil
}
func dePEM(data []byte, blockname string) [][]byte {
var results [][]byte
if strings.Contains(string(data), "BEGIN "+blockname) {
rest := data
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type == blockname {
results = append(results, block.Bytes)
}
}
} else {
results = append(results, data)
}
return results
}
// ReadFileOrURL returns the data from a target which may be either a filename
// or an HTTP(S) URL.
func ReadFileOrURL(target string, client *http.Client) ([]byte, error) {
u, err := url.Parse(target)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return ioutil.ReadFile(target)
}
rsp, err := client.Get(u.String())
if err != nil {
return nil, fmt.Errorf("failed to http.Get(%q): %v", target, err)
}
return ioutil.ReadAll(rsp.Body)
}
// GetIssuer attempts to retrieve the issuer for a certificate, by examining
// the cert's Authority Information Access extension (if present) for the
// issuer's URL and retrieving from there.
func GetIssuer(cert *x509.Certificate, client *http.Client) (*x509.Certificate, error) {
if len(cert.IssuingCertificateURL) == 0 {
return nil, nil
}
issuerURL := cert.IssuingCertificateURL[0]
rsp, err := client.Get(issuerURL)
if err != nil || rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get issuer from %q: %v", issuerURL, err)
}
defer rsp.Body.Close()
body, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read issuer from %q: %v", issuerURL, err)
}
issuers, err := x509.ParseCertificates(body)
if err != nil {
return nil, fmt.Errorf("failed to parse issuer cert: %v", err)
}
return issuers[0], nil
}