diff --git a/ctx.go b/ctx.go index 538679f..f2683e2 100644 --- a/ctx.go +++ b/ctx.go @@ -184,7 +184,12 @@ func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) { return nil, err } - cert, err := LoadCertificateFromPEM(cert_bytes) + certs := SplitPEM(cert_bytes) + if len(certs) == 0 { + return nil, fmt.Errorf("No PEM certificate found in '%s'", cert_file) + } + first, certs := certs[0], certs[1:] + cert, err := LoadCertificateFromPEM(first) if err != nil { return nil, err } @@ -194,6 +199,17 @@ func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) { return nil, err } + for _, pem := range certs { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return nil, err + } + err = ctx.AddChainCertificate(cert) + if err != nil { + return nil, err + } + } + key_bytes, err := ioutil.ReadFile(key_file) if err != nil { return nil, err @@ -285,6 +301,35 @@ type CertificateStore struct { certs []*Certificate } +// Allocate a new, empty CertificateStore +func NewCertificateStore() (*CertificateStore, error) { + s := C.X509_STORE_new() + if s == nil { + return nil, errors.New("failed to allocate X509_STORE") + } + store := &CertificateStore{store: s} + runtime.SetFinalizer(store, func(s *CertificateStore) { + C.X509_STORE_free(s.store) + }) + return store, nil +} + +// Parse a chained PEM file, loading all certificates into the Store. +func (s *CertificateStore) LoadCertificatesFromPEM(data []byte) error { + pems := SplitPEM(data) + for _, pem := range pems { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return err + } + err = s.AddCertificate(cert) + if err != nil { + return err + } + } + return nil +} + // GetCertificateStore returns the context's certificate store that will be // used for peer validation. func (c *Ctx) GetCertificateStore() *CertificateStore { diff --git a/pem.go b/pem.go new file mode 100644 index 0000000..6dad597 --- /dev/null +++ b/pem.go @@ -0,0 +1,32 @@ +// Copyright (C) 2014 Ryan Hileman +// +// 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 openssl + +import ( + "regexp" +) + +var pemSplit *regexp.Regexp = regexp.MustCompile(`(?sm)` + + `(^-----[\s-]*?BEGIN.*?-----$` + + `.*?` + + `^-----[\s-]*?END.*?-----$)`) + +func SplitPEM(data []byte) [][]byte { + var results [][]byte + for _, block := range pemSplit.FindAll(data, -1) { + results = append(results, block) + } + return results +}