mirror of
https://github.com/containers/skopeo.git
synced 2025-09-01 22:58:24 +00:00
Bump github.com/containers/ocicrypt from 1.0.2 to 1.0.3
Bumps [github.com/containers/ocicrypt](https://github.com/containers/ocicrypt) from 1.0.2 to 1.0.3. - [Release notes](https://github.com/containers/ocicrypt/releases) - [Commits](https://github.com/containers/ocicrypt/compare/v1.0.2...v1.0.3) Signed-off-by: dependabot-preview[bot] <support@dependabot.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
committed by
Miloslav Trmač
parent
840c48752e
commit
2e343342d5
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/containers/common v0.15.2
|
github.com/containers/common v0.15.2
|
||||||
github.com/containers/image/v5 v5.5.1
|
github.com/containers/image/v5 v5.5.1
|
||||||
github.com/containers/ocicrypt v1.0.2
|
github.com/containers/ocicrypt v1.0.3
|
||||||
github.com/containers/storage v1.20.2
|
github.com/containers/storage v1.20.2
|
||||||
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f
|
github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/dsnet/compress v0.0.1 // indirect
|
||||||
|
4
go.sum
4
go.sum
@@ -46,6 +46,8 @@ github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDpl
|
|||||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||||
github.com/containers/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
|
github.com/containers/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
|
||||||
github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M=
|
github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M=
|
||||||
|
github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c=
|
||||||
|
github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
|
||||||
github.com/containers/storage v1.20.2 h1:tw/uKRPDnmVrluIzer3dawTFG/bTJLP8IEUyHFhltYk=
|
github.com/containers/storage v1.20.2 h1:tw/uKRPDnmVrluIzer3dawTFG/bTJLP8IEUyHFhltYk=
|
||||||
github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
|
github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
@@ -310,6 +312,8 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
|
|||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
|
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M=
|
||||||
|
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
90
vendor/github.com/containerd/containerd/log/context.go
generated
vendored
90
vendor/github.com/containerd/containerd/log/context.go
generated
vendored
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// G is an alias for GetLogger.
|
|
||||||
//
|
|
||||||
// We may want to define this locally to a package to get package tagged log
|
|
||||||
// messages.
|
|
||||||
G = GetLogger
|
|
||||||
|
|
||||||
// L is an alias for the standard logger.
|
|
||||||
L = logrus.NewEntry(logrus.StandardLogger())
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
loggerKey struct{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// TraceLevel is the log level for tracing. Trace level is lower than debug level,
|
|
||||||
// and is usually used to trace detailed behavior of the program.
|
|
||||||
const TraceLevel = logrus.Level(uint32(logrus.DebugLevel + 1))
|
|
||||||
|
|
||||||
// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
|
|
||||||
// ensure the formatted time is always the same number of characters.
|
|
||||||
const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
|
|
||||||
|
|
||||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
|
||||||
// It supports trace level.
|
|
||||||
func ParseLevel(lvl string) (logrus.Level, error) {
|
|
||||||
if lvl == "trace" {
|
|
||||||
return TraceLevel, nil
|
|
||||||
}
|
|
||||||
return logrus.ParseLevel(lvl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns a new context with the provided logger. Use in
|
|
||||||
// combination with logger.WithField(s) for great effect.
|
|
||||||
func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
|
|
||||||
return context.WithValue(ctx, loggerKey{}, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogger retrieves the current logger from the context. If no logger is
|
|
||||||
// available, the default logger is returned.
|
|
||||||
func GetLogger(ctx context.Context) *logrus.Entry {
|
|
||||||
logger := ctx.Value(loggerKey{})
|
|
||||||
|
|
||||||
if logger == nil {
|
|
||||||
return L
|
|
||||||
}
|
|
||||||
|
|
||||||
return logger.(*logrus.Entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace logs a message at level Trace with the log entry passed-in.
|
|
||||||
func Trace(e *logrus.Entry, args ...interface{}) {
|
|
||||||
level := logrus.Level(atomic.LoadUint32((*uint32)(&e.Logger.Level)))
|
|
||||||
if level >= TraceLevel {
|
|
||||||
e.Debug(args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracef logs a message at level Trace with the log entry passed-in.
|
|
||||||
func Tracef(e *logrus.Entry, format string, args ...interface{}) {
|
|
||||||
level := logrus.Level(atomic.LoadUint32((*uint32)(&e.Logger.Level)))
|
|
||||||
if level >= TraceLevel {
|
|
||||||
e.Debugf(format, args...)
|
|
||||||
}
|
|
||||||
}
|
|
229
vendor/github.com/containerd/containerd/platforms/compare.go
generated
vendored
229
vendor/github.com/containerd/containerd/platforms/compare.go
generated
vendored
@@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
import specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
|
|
||||||
// MatchComparer is able to match and compare platforms to
|
|
||||||
// filter and sort platforms.
|
|
||||||
type MatchComparer interface {
|
|
||||||
Matcher
|
|
||||||
|
|
||||||
Less(specs.Platform, specs.Platform) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only returns a match comparer for a single platform
|
|
||||||
// using default resolution logic for the platform.
|
|
||||||
//
|
|
||||||
// For ARMv8, will also match ARMv7, ARMv6 and ARMv5 (for 32bit runtimes)
|
|
||||||
// For ARMv7, will also match ARMv6 and ARMv5
|
|
||||||
// For ARMv6, will also match ARMv5
|
|
||||||
func Only(platform specs.Platform) MatchComparer {
|
|
||||||
platform = Normalize(platform)
|
|
||||||
if platform.Architecture == "arm" {
|
|
||||||
if platform.Variant == "v8" {
|
|
||||||
return orderedPlatformComparer{
|
|
||||||
matchers: []Matcher{
|
|
||||||
&matcher{
|
|
||||||
Platform: platform,
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v7",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v5",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if platform.Variant == "v7" {
|
|
||||||
return orderedPlatformComparer{
|
|
||||||
matchers: []Matcher{
|
|
||||||
&matcher{
|
|
||||||
Platform: platform,
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v5",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if platform.Variant == "v6" {
|
|
||||||
return orderedPlatformComparer{
|
|
||||||
matchers: []Matcher{
|
|
||||||
&matcher{
|
|
||||||
Platform: platform,
|
|
||||||
},
|
|
||||||
&matcher{
|
|
||||||
Platform: specs.Platform{
|
|
||||||
Architecture: platform.Architecture,
|
|
||||||
OS: platform.OS,
|
|
||||||
OSVersion: platform.OSVersion,
|
|
||||||
OSFeatures: platform.OSFeatures,
|
|
||||||
Variant: "v5",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return singlePlatformComparer{
|
|
||||||
Matcher: &matcher{
|
|
||||||
Platform: platform,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ordered returns a platform MatchComparer which matches any of the platforms
|
|
||||||
// but orders them in order they are provided.
|
|
||||||
func Ordered(platforms ...specs.Platform) MatchComparer {
|
|
||||||
matchers := make([]Matcher, len(platforms))
|
|
||||||
for i := range platforms {
|
|
||||||
matchers[i] = NewMatcher(platforms[i])
|
|
||||||
}
|
|
||||||
return orderedPlatformComparer{
|
|
||||||
matchers: matchers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any returns a platform MatchComparer which matches any of the platforms
|
|
||||||
// with no preference for ordering.
|
|
||||||
func Any(platforms ...specs.Platform) MatchComparer {
|
|
||||||
matchers := make([]Matcher, len(platforms))
|
|
||||||
for i := range platforms {
|
|
||||||
matchers[i] = NewMatcher(platforms[i])
|
|
||||||
}
|
|
||||||
return anyPlatformComparer{
|
|
||||||
matchers: matchers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All is a platform MatchComparer which matches all platforms
|
|
||||||
// with preference for ordering.
|
|
||||||
var All MatchComparer = allPlatformComparer{}
|
|
||||||
|
|
||||||
type singlePlatformComparer struct {
|
|
||||||
Matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c singlePlatformComparer) Less(p1, p2 specs.Platform) bool {
|
|
||||||
return c.Match(p1) && !c.Match(p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
type orderedPlatformComparer struct {
|
|
||||||
matchers []Matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
|
|
||||||
for _, m := range c.matchers {
|
|
||||||
if m.Match(platform) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
|
|
||||||
for _, m := range c.matchers {
|
|
||||||
p1m := m.Match(p1)
|
|
||||||
p2m := m.Match(p2)
|
|
||||||
if p1m && !p2m {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p1m || p2m {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type anyPlatformComparer struct {
|
|
||||||
matchers []Matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c anyPlatformComparer) Match(platform specs.Platform) bool {
|
|
||||||
for _, m := range c.matchers {
|
|
||||||
if m.Match(platform) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
|
|
||||||
var p1m, p2m bool
|
|
||||||
for _, m := range c.matchers {
|
|
||||||
if !p1m && m.Match(p1) {
|
|
||||||
p1m = true
|
|
||||||
}
|
|
||||||
if !p2m && m.Match(p2) {
|
|
||||||
p2m = true
|
|
||||||
}
|
|
||||||
if p1m && p2m {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If one matches, and the other does, sort match first
|
|
||||||
return p1m && !p2m
|
|
||||||
}
|
|
||||||
|
|
||||||
type allPlatformComparer struct{}
|
|
||||||
|
|
||||||
func (allPlatformComparer) Match(specs.Platform) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
117
vendor/github.com/containerd/containerd/platforms/cpuinfo.go
generated
vendored
117
vendor/github.com/containerd/containerd/platforms/cpuinfo.go
generated
vendored
@@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
|
||||||
"github.com/containerd/containerd/log"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Present the ARM instruction set architecture, eg: v7, v8
|
|
||||||
var cpuVariant string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if isArmArch(runtime.GOARCH) {
|
|
||||||
cpuVariant = getCPUVariant()
|
|
||||||
} else {
|
|
||||||
cpuVariant = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For Linux, the kernel has already detected the ABI, ISA and Features.
|
|
||||||
// So we don't need to access the ARM registers to detect platform information
|
|
||||||
// by ourselves. We can just parse these information from /proc/cpuinfo
|
|
||||||
func getCPUInfo(pattern string) (info string, err error) {
|
|
||||||
if !isLinuxOS(runtime.GOOS) {
|
|
||||||
return "", errors.Wrapf(errdefs.ErrNotImplemented, "getCPUInfo for OS %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
cpuinfo, err := os.Open("/proc/cpuinfo")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer cpuinfo.Close()
|
|
||||||
|
|
||||||
// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
|
|
||||||
// the first core is enough.
|
|
||||||
scanner := bufio.NewScanner(cpuinfo)
|
|
||||||
for scanner.Scan() {
|
|
||||||
newline := scanner.Text()
|
|
||||||
list := strings.Split(newline, ":")
|
|
||||||
|
|
||||||
if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
|
|
||||||
return strings.TrimSpace(list[1]), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the scanner encountered errors
|
|
||||||
err = scanner.Err()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.Wrapf(errdefs.ErrNotFound, "getCPUInfo for pattern: %s", pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCPUVariant() string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
|
|
||||||
// runtime.GOARCH to determine the variants
|
|
||||||
var variant string
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "arm64":
|
|
||||||
variant = "v8"
|
|
||||||
case "arm":
|
|
||||||
variant = "v7"
|
|
||||||
default:
|
|
||||||
variant = "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
return variant
|
|
||||||
}
|
|
||||||
|
|
||||||
variant, err := getCPUInfo("Cpu architecture")
|
|
||||||
if err != nil {
|
|
||||||
log.L.WithError(err).Error("failure getting variant")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
switch variant {
|
|
||||||
case "8", "AArch64":
|
|
||||||
variant = "v8"
|
|
||||||
case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
|
|
||||||
variant = "v7"
|
|
||||||
case "6", "6TEJ":
|
|
||||||
variant = "v6"
|
|
||||||
case "5", "5T", "5TE", "5TEJ":
|
|
||||||
variant = "v5"
|
|
||||||
case "4", "4T":
|
|
||||||
variant = "v4"
|
|
||||||
case "3":
|
|
||||||
variant = "v3"
|
|
||||||
default:
|
|
||||||
variant = "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
return variant
|
|
||||||
}
|
|
114
vendor/github.com/containerd/containerd/platforms/database.go
generated
vendored
114
vendor/github.com/containerd/containerd/platforms/database.go
generated
vendored
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// isLinuxOS returns true if the operating system is Linux.
|
|
||||||
//
|
|
||||||
// The OS value should be normalized before calling this function.
|
|
||||||
func isLinuxOS(os string) bool {
|
|
||||||
return os == "linux"
|
|
||||||
}
|
|
||||||
|
|
||||||
// These function are generated from https://golang.org/src/go/build/syslist.go.
|
|
||||||
//
|
|
||||||
// We use switch statements because they are slightly faster than map lookups
|
|
||||||
// and use a little less memory.
|
|
||||||
|
|
||||||
// isKnownOS returns true if we know about the operating system.
|
|
||||||
//
|
|
||||||
// The OS value should be normalized before calling this function.
|
|
||||||
func isKnownOS(os string) bool {
|
|
||||||
switch os {
|
|
||||||
case "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// isArmArch returns true if the architecture is ARM.
|
|
||||||
//
|
|
||||||
// The arch value should be normalized before being passed to this function.
|
|
||||||
func isArmArch(arch string) bool {
|
|
||||||
switch arch {
|
|
||||||
case "arm", "arm64":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// isKnownArch returns true if we know about the architecture.
|
|
||||||
//
|
|
||||||
// The arch value should be normalized before being passed to this function.
|
|
||||||
func isKnownArch(arch string) bool {
|
|
||||||
switch arch {
|
|
||||||
case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeOS(os string) string {
|
|
||||||
if os == "" {
|
|
||||||
return runtime.GOOS
|
|
||||||
}
|
|
||||||
os = strings.ToLower(os)
|
|
||||||
|
|
||||||
switch os {
|
|
||||||
case "macos":
|
|
||||||
os = "darwin"
|
|
||||||
}
|
|
||||||
return os
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalizeArch normalizes the architecture.
|
|
||||||
func normalizeArch(arch, variant string) (string, string) {
|
|
||||||
arch, variant = strings.ToLower(arch), strings.ToLower(variant)
|
|
||||||
switch arch {
|
|
||||||
case "i386":
|
|
||||||
arch = "386"
|
|
||||||
variant = ""
|
|
||||||
case "x86_64", "x86-64":
|
|
||||||
arch = "amd64"
|
|
||||||
variant = ""
|
|
||||||
case "aarch64", "arm64":
|
|
||||||
arch = "arm64"
|
|
||||||
switch variant {
|
|
||||||
case "8", "v8":
|
|
||||||
variant = ""
|
|
||||||
}
|
|
||||||
case "armhf":
|
|
||||||
arch = "arm"
|
|
||||||
variant = "v7"
|
|
||||||
case "armel":
|
|
||||||
arch = "arm"
|
|
||||||
variant = "v6"
|
|
||||||
case "arm":
|
|
||||||
switch variant {
|
|
||||||
case "", "7":
|
|
||||||
variant = "v7"
|
|
||||||
case "5", "6", "8":
|
|
||||||
variant = "v" + variant
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return arch, variant
|
|
||||||
}
|
|
38
vendor/github.com/containerd/containerd/platforms/defaults.go
generated
vendored
38
vendor/github.com/containerd/containerd/platforms/defaults.go
generated
vendored
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultString returns the default string specifier for the platform.
|
|
||||||
func DefaultString() string {
|
|
||||||
return Format(DefaultSpec())
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultSpec returns the current platform's default platform specification.
|
|
||||||
func DefaultSpec() specs.Platform {
|
|
||||||
return specs.Platform{
|
|
||||||
OS: runtime.GOOS,
|
|
||||||
Architecture: runtime.GOARCH,
|
|
||||||
// The Variant field will be empty if arch != ARM.
|
|
||||||
Variant: cpuVariant,
|
|
||||||
}
|
|
||||||
}
|
|
24
vendor/github.com/containerd/containerd/platforms/defaults_unix.go
generated
vendored
24
vendor/github.com/containerd/containerd/platforms/defaults_unix.go
generated
vendored
@@ -1,24 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
// Default returns the default matcher for the platform.
|
|
||||||
func Default() MatchComparer {
|
|
||||||
return Only(DefaultSpec())
|
|
||||||
}
|
|
31
vendor/github.com/containerd/containerd/platforms/defaults_windows.go
generated
vendored
31
vendor/github.com/containerd/containerd/platforms/defaults_windows.go
generated
vendored
@@ -1,31 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms
|
|
||||||
|
|
||||||
import (
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Default returns the default matcher for the platform.
|
|
||||||
func Default() MatchComparer {
|
|
||||||
return Ordered(DefaultSpec(), specs.Platform{
|
|
||||||
OS: "linux",
|
|
||||||
Architecture: "amd64",
|
|
||||||
})
|
|
||||||
}
|
|
279
vendor/github.com/containerd/containerd/platforms/platforms.go
generated
vendored
279
vendor/github.com/containerd/containerd/platforms/platforms.go
generated
vendored
@@ -1,279 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
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 platforms provides a toolkit for normalizing, matching and
|
|
||||||
// specifying container platforms.
|
|
||||||
//
|
|
||||||
// Centered around OCI platform specifications, we define a string-based
|
|
||||||
// specifier syntax that can be used for user input. With a specifier, users
|
|
||||||
// only need to specify the parts of the platform that are relevant to their
|
|
||||||
// context, providing an operating system or architecture or both.
|
|
||||||
//
|
|
||||||
// How do I use this package?
|
|
||||||
//
|
|
||||||
// The vast majority of use cases should simply use the match function with
|
|
||||||
// user input. The first step is to parse a specifier into a matcher:
|
|
||||||
//
|
|
||||||
// m, err := Parse("linux")
|
|
||||||
// if err != nil { ... }
|
|
||||||
//
|
|
||||||
// Once you have a matcher, use it to match against the platform declared by a
|
|
||||||
// component, typically from an image or runtime. Since extracting an images
|
|
||||||
// platform is a little more involved, we'll use an example against the
|
|
||||||
// platform default:
|
|
||||||
//
|
|
||||||
// if ok := m.Match(Default()); !ok { /* doesn't match */ }
|
|
||||||
//
|
|
||||||
// This can be composed in loops for resolving runtimes or used as a filter for
|
|
||||||
// fetch and select images.
|
|
||||||
//
|
|
||||||
// More details of the specifier syntax and platform spec follow.
|
|
||||||
//
|
|
||||||
// Declaring Platform Support
|
|
||||||
//
|
|
||||||
// Components that have strict platform requirements should use the OCI
|
|
||||||
// platform specification to declare their support. Typically, this will be
|
|
||||||
// images and runtimes that should make these declaring which platform they
|
|
||||||
// support specifically. This looks roughly as follows:
|
|
||||||
//
|
|
||||||
// type Platform struct {
|
|
||||||
// Architecture string
|
|
||||||
// OS string
|
|
||||||
// Variant string
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Most images and runtimes should at least set Architecture and OS, according
|
|
||||||
// to their GOARCH and GOOS values, respectively (follow the OCI image
|
|
||||||
// specification when in doubt). ARM should set variant under certain
|
|
||||||
// discussions, which are outlined below.
|
|
||||||
//
|
|
||||||
// Platform Specifiers
|
|
||||||
//
|
|
||||||
// While the OCI platform specifications provide a tool for components to
|
|
||||||
// specify structured information, user input typically doesn't need the full
|
|
||||||
// context and much can be inferred. To solve this problem, we introduced
|
|
||||||
// "specifiers". A specifier has the format
|
|
||||||
// `<os>|<arch>|<os>/<arch>[/<variant>]`. The user can provide either the
|
|
||||||
// operating system or the architecture or both.
|
|
||||||
//
|
|
||||||
// An example of a common specifier is `linux/amd64`. If the host has a default
|
|
||||||
// of runtime that matches this, the user can simply provide the component that
|
|
||||||
// matters. For example, if a image provides amd64 and arm64 support, the
|
|
||||||
// operating system, `linux` can be inferred, so they only have to provide
|
|
||||||
// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
|
|
||||||
// where the architecture may be known but a runtime may support images from
|
|
||||||
// different operating systems.
|
|
||||||
//
|
|
||||||
// Normalization
|
|
||||||
//
|
|
||||||
// Because not all users are familiar with the way the Go runtime represents
|
|
||||||
// platforms, several normalizations have been provided to make this package
|
|
||||||
// easier to user.
|
|
||||||
//
|
|
||||||
// The following are performed for architectures:
|
|
||||||
//
|
|
||||||
// Value Normalized
|
|
||||||
// aarch64 arm64
|
|
||||||
// armhf arm
|
|
||||||
// armel arm/v6
|
|
||||||
// i386 386
|
|
||||||
// x86_64 amd64
|
|
||||||
// x86-64 amd64
|
|
||||||
//
|
|
||||||
// We also normalize the operating system `macos` to `darwin`.
|
|
||||||
//
|
|
||||||
// ARM Support
|
|
||||||
//
|
|
||||||
// To qualify ARM architecture, the Variant field is used to qualify the arm
|
|
||||||
// version. The most common arm version, v7, is represented without the variant
|
|
||||||
// unless it is explicitly provided. This is treated as equivalent to armhf. A
|
|
||||||
// previous architecture, armel, will be normalized to arm/v6.
|
|
||||||
//
|
|
||||||
// While these normalizations are provided, their support on arm platforms has
|
|
||||||
// not yet been fully implemented and tested.
|
|
||||||
package platforms
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Matcher matches platforms specifications, provided by an image or runtime.
|
|
||||||
type Matcher interface {
|
|
||||||
Match(platform specs.Platform) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMatcher returns a simple matcher based on the provided platform
|
|
||||||
// specification. The returned matcher only looks for equality based on os,
|
|
||||||
// architecture and variant.
|
|
||||||
//
|
|
||||||
// One may implement their own matcher if this doesn't provide the required
|
|
||||||
// functionality.
|
|
||||||
//
|
|
||||||
// Applications should opt to use `Match` over directly parsing specifiers.
|
|
||||||
func NewMatcher(platform specs.Platform) Matcher {
|
|
||||||
return &matcher{
|
|
||||||
Platform: Normalize(platform),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type matcher struct {
|
|
||||||
specs.Platform
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *matcher) Match(platform specs.Platform) bool {
|
|
||||||
normalized := Normalize(platform)
|
|
||||||
return m.OS == normalized.OS &&
|
|
||||||
m.Architecture == normalized.Architecture &&
|
|
||||||
m.Variant == normalized.Variant
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *matcher) String() string {
|
|
||||||
return Format(m.Platform)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses the platform specifier syntax into a platform declaration.
|
|
||||||
//
|
|
||||||
// Platform specifiers are in the format `<os>|<arch>|<os>/<arch>[/<variant>]`.
|
|
||||||
// The minimum required information for a platform specifier is the operating
|
|
||||||
// system or architecture. If there is only a single string (no slashes), the
|
|
||||||
// value will be matched against the known set of operating systems, then fall
|
|
||||||
// back to the known set of architectures. The missing component will be
|
|
||||||
// inferred based on the local environment.
|
|
||||||
func Parse(specifier string) (specs.Platform, error) {
|
|
||||||
if strings.Contains(specifier, "*") {
|
|
||||||
// TODO(stevvooe): need to work out exact wildcard handling
|
|
||||||
return specs.Platform{}, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: wildcards not yet supported", specifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(specifier, "/")
|
|
||||||
|
|
||||||
for _, part := range parts {
|
|
||||||
if !specifierRe.MatchString(part) {
|
|
||||||
return specs.Platform{}, errors.Wrapf(errdefs.ErrInvalidArgument, "%q is an invalid component of %q: platform specifier component must match %q", part, specifier, specifierRe.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var p specs.Platform
|
|
||||||
switch len(parts) {
|
|
||||||
case 1:
|
|
||||||
// in this case, we will test that the value might be an OS, then look
|
|
||||||
// it up. If it is not known, we'll treat it as an architecture. Since
|
|
||||||
// we have very little information about the platform here, we are
|
|
||||||
// going to be a little more strict if we don't know about the argument
|
|
||||||
// value.
|
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
if isKnownOS(p.OS) {
|
|
||||||
// picks a default architecture
|
|
||||||
p.Architecture = runtime.GOARCH
|
|
||||||
if p.Architecture == "arm" {
|
|
||||||
// TODO(stevvooe): Resolve arm variant, if not v6 (default)
|
|
||||||
return specs.Platform{}, errors.Wrapf(errdefs.ErrNotImplemented, "arm support not fully implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Architecture, p.Variant = normalizeArch(parts[0], "")
|
|
||||||
if p.Architecture == "arm" && p.Variant == "v7" {
|
|
||||||
p.Variant = ""
|
|
||||||
}
|
|
||||||
if isKnownArch(p.Architecture) {
|
|
||||||
p.OS = runtime.GOOS
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return specs.Platform{}, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: unknown operating system or architecture", specifier)
|
|
||||||
case 2:
|
|
||||||
// In this case, we treat as a regular os/arch pair. We don't care
|
|
||||||
// about whether or not we know of the platform.
|
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
p.Architecture, p.Variant = normalizeArch(parts[1], "")
|
|
||||||
if p.Architecture == "arm" && p.Variant == "v7" {
|
|
||||||
p.Variant = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
case 3:
|
|
||||||
// we have a fully specified variant, this is rare
|
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
|
|
||||||
if p.Architecture == "arm64" && p.Variant == "" {
|
|
||||||
p.Variant = "v8"
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return specs.Platform{}, errors.Wrapf(errdefs.ErrInvalidArgument, "%q: cannot parse platform specifier", specifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParse is like Parses but panics if the specifier cannot be parsed.
|
|
||||||
// Simplifies initialization of global variables.
|
|
||||||
func MustParse(specifier string) specs.Platform {
|
|
||||||
p, err := Parse(specifier)
|
|
||||||
if err != nil {
|
|
||||||
panic("platform: Parse(" + strconv.Quote(specifier) + "): " + err.Error())
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format returns a string specifier from the provided platform specification.
|
|
||||||
func Format(platform specs.Platform) string {
|
|
||||||
if platform.OS == "" {
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
return joinNotEmpty(platform.OS, platform.Architecture, platform.Variant)
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinNotEmpty(s ...string) string {
|
|
||||||
var ss []string
|
|
||||||
for _, s := range s {
|
|
||||||
if s == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ss = append(ss, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(ss, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize validates and translate the platform to the canonical value.
|
|
||||||
//
|
|
||||||
// For example, if "Aarch64" is encountered, we change it to "arm64" or if
|
|
||||||
// "x86_64" is encountered, it becomes "amd64".
|
|
||||||
func Normalize(platform specs.Platform) specs.Platform {
|
|
||||||
platform.OS = normalizeOS(platform.OS)
|
|
||||||
platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
|
|
||||||
|
|
||||||
// these fields are deprecated, remove them
|
|
||||||
platform.OSFeatures = nil
|
|
||||||
platform.OSVersion = ""
|
|
||||||
|
|
||||||
return platform
|
|
||||||
}
|
|
22
vendor/github.com/containers/ocicrypt/.travis.yml
generated
vendored
Normal file
22
vendor/github.com/containers/ocicrypt/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
dist: xenial
|
||||||
|
language: go
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
|
||||||
|
go:
|
||||||
|
- "1.13.x"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
|
||||||
|
go_import_path: github.com/containers/ocicrypt
|
||||||
|
|
||||||
|
install:
|
||||||
|
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.19.1
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make
|
||||||
|
- make check
|
||||||
|
- make test
|
3
vendor/github.com/containers/ocicrypt/SECURITY.md
generated
vendored
Normal file
3
vendor/github.com/containers/ocicrypt/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## Security and Disclosure Information Policy for the OCIcrypt Library Project
|
||||||
|
|
||||||
|
The OCIcrypt Library Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects.
|
8
vendor/github.com/containers/ocicrypt/go.mod
generated
vendored
8
vendor/github.com/containers/ocicrypt/go.mod
generated
vendored
@@ -3,15 +3,13 @@ module github.com/containers/ocicrypt
|
|||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/containerd/containerd v1.2.10
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||||
github.com/opencontainers/image-spec v1.0.1
|
github.com/opencontainers/image-spec v1.0.1
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
|
||||||
github.com/stretchr/testify v1.3.0 // indirect
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
|
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||||
google.golang.org/grpc v1.24.0 // indirect
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1
|
gopkg.in/square/go-jose.v2 v2.3.1
|
||||||
gotest.tools v2.2.0+incompatible // indirect
|
|
||||||
)
|
)
|
||||||
|
36
vendor/github.com/containers/ocicrypt/go.sum
generated
vendored
36
vendor/github.com/containers/ocicrypt/go.sum
generated
vendored
@@ -1,23 +1,7 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/containerd/containerd v1.2.10 h1:liQDhXqIn7y6cJ/7qBgOaZsiTZJc56/wkkhDBiDBRDw=
|
|
||||||
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
|
|
||||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||||
@@ -26,22 +10,16 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M=
|
||||||
|
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -49,15 +27,5 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/p
|
|||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
|
||||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
|
4
vendor/github.com/containers/ocicrypt/gpg.go
generated
vendored
4
vendor/github.com/containers/ocicrypt/gpg.go
generated
vendored
@@ -170,7 +170,7 @@ func (gc *gpgv2Client) getKeyDetails(option string, keyid uint64) ([]byte, bool,
|
|||||||
var args []string
|
var args []string
|
||||||
|
|
||||||
if gc.gpgHomeDir != "" {
|
if gc.gpgHomeDir != "" {
|
||||||
args = append([]string{"--homedir", gc.gpgHomeDir})
|
args = []string{"--homedir", gc.gpgHomeDir}
|
||||||
}
|
}
|
||||||
args = append(args, option, fmt.Sprintf("0x%x", keyid))
|
args = append(args, option, fmt.Sprintf("0x%x", keyid))
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ func (gc *gpgv1Client) getKeyDetails(option string, keyid uint64) ([]byte, bool,
|
|||||||
var args []string
|
var args []string
|
||||||
|
|
||||||
if gc.gpgHomeDir != "" {
|
if gc.gpgHomeDir != "" {
|
||||||
args = append([]string{"--homedir", gc.gpgHomeDir})
|
args = []string{"--homedir", gc.gpgHomeDir}
|
||||||
}
|
}
|
||||||
args = append(args, option, fmt.Sprintf("0x%x", keyid))
|
args = append(args, option, fmt.Sprintf("0x%x", keyid))
|
||||||
|
|
||||||
|
66
vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go
generated
vendored
66
vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go
generated
vendored
@@ -1,19 +1,16 @@
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/containerd/platforms"
|
|
||||||
"github.com/containers/ocicrypt"
|
"github.com/containers/ocicrypt"
|
||||||
encconfig "github.com/containers/ocicrypt/config"
|
encconfig "github.com/containers/ocicrypt/config"
|
||||||
encutils "github.com/containers/ocicrypt/utils"
|
encutils "github.com/containers/ocicrypt/utils"
|
||||||
|
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -66,6 +63,23 @@ func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, er
|
|||||||
return gpgRecipients, pubkeys, x509s, nil
|
return gpgRecipients, pubkeys, x509s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processx509Certs processes x509 certificate files
|
||||||
|
func processx509Certs(keys []string) ([][]byte, error) {
|
||||||
|
var x509s [][]byte
|
||||||
|
for _, key := range keys {
|
||||||
|
tmp, err := ioutil.ReadFile(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Unable to read file")
|
||||||
|
}
|
||||||
|
if !encutils.IsCertificate(tmp) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x509s = append(x509s, tmp)
|
||||||
|
|
||||||
|
}
|
||||||
|
return x509s, nil
|
||||||
|
}
|
||||||
|
|
||||||
// processPwdString process a password that may be in any of the following formats:
|
// processPwdString process a password that may be in any of the following formats:
|
||||||
// - file=<passwordfile>
|
// - file=<passwordfile>
|
||||||
// - pass=<password>
|
// - pass=<password>
|
||||||
@@ -141,33 +155,14 @@ func processPrivateKeyFiles(keyFilesAndPwds []string) ([][]byte, [][]byte, [][]b
|
|||||||
gpgSecretKeyRingFiles = append(gpgSecretKeyRingFiles, tmp)
|
gpgSecretKeyRingFiles = append(gpgSecretKeyRingFiles, tmp)
|
||||||
gpgSecretKeyPasswords = append(gpgSecretKeyPasswords, password)
|
gpgSecretKeyPasswords = append(gpgSecretKeyPasswords, password)
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("unidentified private key in file %s (password=%s)", keyfile, string(password))
|
// ignore if file is not recognized, so as not to error if additional
|
||||||
|
// metadata/cert files exists
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privkeys, privkeysPasswords, nil
|
return gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privkeys, privkeysPasswords, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createGPGClient(context context.Context) (ocicrypt.GPGClient, error) {
|
|
||||||
return ocicrypt.NewGPGClient(context.Value("gpg-version").(string), context.Value("gpg-homedir").(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGPGPrivateKeys(context context.Context, gpgSecretKeyRingFiles [][]byte, descs []ocispec.Descriptor, mustFindKey bool) (gpgPrivKeys [][]byte, gpgPrivKeysPwds [][]byte, err error) {
|
|
||||||
gpgClient, err := createGPGClient(context)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var gpgVault ocicrypt.GPGVault
|
|
||||||
if len(gpgSecretKeyRingFiles) > 0 {
|
|
||||||
gpgVault = ocicrypt.NewGPGVault()
|
|
||||||
err = gpgVault.AddSecretKeyRingDataArray(gpgSecretKeyRingFiles)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ocicrypt.GPGGetPrivateKey(descs, gpgClient, gpgVault, mustFindKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateDecryptCryptoConfig creates the CryptoConfig object that contains the necessary
|
// CreateDecryptCryptoConfig creates the CryptoConfig object that contains the necessary
|
||||||
// information to perform decryption from command line options and possibly
|
// information to perform decryption from command line options and possibly
|
||||||
// LayerInfos describing the image and helping us to query for the PGP decryption keys
|
// LayerInfos describing the image and helping us to query for the PGP decryption keys
|
||||||
@@ -180,6 +175,13 @@ func CreateDecryptCryptoConfig(keys []string, decRecipients []string) (encconfig
|
|||||||
return encconfig.CryptoConfig{}, err
|
return encconfig.CryptoConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x509 certs can also be passed in via keys
|
||||||
|
x509FromKeys, err := processx509Certs(keys)
|
||||||
|
if err != nil {
|
||||||
|
return encconfig.CryptoConfig{}, err
|
||||||
|
}
|
||||||
|
x509s = append(x509s, x509FromKeys...)
|
||||||
|
|
||||||
gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privKeys, privKeysPasswords, err := processPrivateKeyFiles(keys)
|
gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privKeys, privKeysPasswords, err := processPrivateKeyFiles(keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return encconfig.CryptoConfig{}, err
|
return encconfig.CryptoConfig{}, err
|
||||||
@@ -236,20 +238,6 @@ func CreateDecryptCryptoConfig(keys []string, decRecipients []string) (encconfig
|
|||||||
return encconfig.CombineCryptoConfigs(ccs), nil
|
return encconfig.CombineCryptoConfigs(ccs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsePlatformArray parses an array of specifiers and converts them into an array of specs.Platform
|
|
||||||
func parsePlatformArray(specifiers []string) ([]ocispec.Platform, error) {
|
|
||||||
var speclist []ocispec.Platform
|
|
||||||
|
|
||||||
for _, specifier := range specifiers {
|
|
||||||
spec, err := platforms.Parse(specifier)
|
|
||||||
if err != nil {
|
|
||||||
return []ocispec.Platform{}, err
|
|
||||||
}
|
|
||||||
speclist = append(speclist, spec)
|
|
||||||
}
|
|
||||||
return speclist, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateCryptoConfig from the list of recipient strings and list of key paths of private keys
|
// CreateCryptoConfig from the list of recipient strings and list of key paths of private keys
|
||||||
func CreateCryptoConfig(recipients []string, keys []string) (encconfig.CryptoConfig, error) {
|
func CreateCryptoConfig(recipients []string, keys []string) (encconfig.CryptoConfig, error) {
|
||||||
var decryptCc *encconfig.CryptoConfig
|
var decryptCc *encconfig.CryptoConfig
|
||||||
|
2
vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go
generated
vendored
2
vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go
generated
vendored
@@ -23,8 +23,8 @@ import (
|
|||||||
"github.com/containers/ocicrypt/config"
|
"github.com/containers/ocicrypt/config"
|
||||||
"github.com/containers/ocicrypt/keywrap"
|
"github.com/containers/ocicrypt/keywrap"
|
||||||
"github.com/containers/ocicrypt/utils"
|
"github.com/containers/ocicrypt/utils"
|
||||||
"github.com/fullsailor/pkcs7"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"go.mozilla.org/pkcs7"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pkcs7KeyWrapper struct {
|
type pkcs7KeyWrapper struct {
|
||||||
|
7
vendor/github.com/fullsailor/pkcs7/.travis.yml
generated
vendored
7
vendor/github.com/fullsailor/pkcs7/.travis.yml
generated
vendored
@@ -1,7 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.8
|
|
||||||
- 1.9
|
|
||||||
- "1.10"
|
|
||||||
- tip
|
|
8
vendor/github.com/fullsailor/pkcs7/README.md
generated
vendored
8
vendor/github.com/fullsailor/pkcs7/README.md
generated
vendored
@@ -1,8 +0,0 @@
|
|||||||
# pkcs7
|
|
||||||
|
|
||||||
[](https://godoc.org/github.com/fullsailor/pkcs7)
|
|
||||||
[](https://travis-ci.org/fullsailor/pkcs7)
|
|
||||||
|
|
||||||
pkcs7 implements parsing and creating signed and enveloped messages.
|
|
||||||
|
|
||||||
- Documentation on [GoDoc](http://godoc.org/github.com/fullsailor/pkcs7)
|
|
962
vendor/github.com/fullsailor/pkcs7/pkcs7.go
generated
vendored
962
vendor/github.com/fullsailor/pkcs7/pkcs7.go
generated
vendored
@@ -1,962 +0,0 @@
|
|||||||
// Package pkcs7 implements parsing and generation of some PKCS#7 structures.
|
|
||||||
package pkcs7
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/des"
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/asn1"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
_ "crypto/sha1" // for crypto.SHA1
|
|
||||||
)
|
|
||||||
|
|
||||||
// PKCS7 Represents a PKCS7 structure
|
|
||||||
type PKCS7 struct {
|
|
||||||
Content []byte
|
|
||||||
Certificates []*x509.Certificate
|
|
||||||
CRLs []pkix.CertificateList
|
|
||||||
Signers []signerInfo
|
|
||||||
raw interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type contentInfo struct {
|
|
||||||
ContentType asn1.ObjectIdentifier
|
|
||||||
Content asn1.RawValue `asn1:"explicit,optional,tag:0"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUnsupportedContentType is returned when a PKCS7 content is not supported.
|
|
||||||
// Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2),
|
|
||||||
// and Enveloped Data are supported (1.2.840.113549.1.7.3)
|
|
||||||
var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type")
|
|
||||||
|
|
||||||
type unsignedData []byte
|
|
||||||
|
|
||||||
var (
|
|
||||||
oidData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
|
|
||||||
oidSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
|
|
||||||
oidEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
|
|
||||||
oidSignedAndEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 4}
|
|
||||||
oidDigestedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 5}
|
|
||||||
oidEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
|
|
||||||
oidAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
|
|
||||||
oidAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
|
|
||||||
oidAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
|
|
||||||
)
|
|
||||||
|
|
||||||
type signedData struct {
|
|
||||||
Version int `asn1:"default:1"`
|
|
||||||
DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"`
|
|
||||||
ContentInfo contentInfo
|
|
||||||
Certificates rawCertificates `asn1:"optional,tag:0"`
|
|
||||||
CRLs []pkix.CertificateList `asn1:"optional,tag:1"`
|
|
||||||
SignerInfos []signerInfo `asn1:"set"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type rawCertificates struct {
|
|
||||||
Raw asn1.RawContent
|
|
||||||
}
|
|
||||||
|
|
||||||
type envelopedData struct {
|
|
||||||
Version int
|
|
||||||
RecipientInfos []recipientInfo `asn1:"set"`
|
|
||||||
EncryptedContentInfo encryptedContentInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type recipientInfo struct {
|
|
||||||
Version int
|
|
||||||
IssuerAndSerialNumber issuerAndSerial
|
|
||||||
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
EncryptedKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type encryptedContentInfo struct {
|
|
||||||
ContentType asn1.ObjectIdentifier
|
|
||||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type attribute struct {
|
|
||||||
Type asn1.ObjectIdentifier
|
|
||||||
Value asn1.RawValue `asn1:"set"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type issuerAndSerial struct {
|
|
||||||
IssuerName asn1.RawValue
|
|
||||||
SerialNumber *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageDigestMismatchError is returned when the signer data digest does not
|
|
||||||
// match the computed digest for the contained content
|
|
||||||
type MessageDigestMismatchError struct {
|
|
||||||
ExpectedDigest []byte
|
|
||||||
ActualDigest []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err *MessageDigestMismatchError) Error() string {
|
|
||||||
return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest)
|
|
||||||
}
|
|
||||||
|
|
||||||
type signerInfo struct {
|
|
||||||
Version int `asn1:"default:1"`
|
|
||||||
IssuerAndSerialNumber issuerAndSerial
|
|
||||||
DigestAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
AuthenticatedAttributes []attribute `asn1:"optional,tag:0"`
|
|
||||||
DigestEncryptionAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
EncryptedDigest []byte
|
|
||||||
UnauthenticatedAttributes []attribute `asn1:"optional,tag:1"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse decodes a DER encoded PKCS7 package
|
|
||||||
func Parse(data []byte) (p7 *PKCS7, err error) {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil, errors.New("pkcs7: input data is empty")
|
|
||||||
}
|
|
||||||
var info contentInfo
|
|
||||||
der, err := ber2der(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rest, err := asn1.Unmarshal(der, &info)
|
|
||||||
if len(rest) > 0 {
|
|
||||||
err = asn1.SyntaxError{Msg: "trailing data"}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// fmt.Printf("--> Content Type: %s", info.ContentType)
|
|
||||||
switch {
|
|
||||||
case info.ContentType.Equal(oidSignedData):
|
|
||||||
return parseSignedData(info.Content.Bytes)
|
|
||||||
case info.ContentType.Equal(oidEnvelopedData):
|
|
||||||
return parseEnvelopedData(info.Content.Bytes)
|
|
||||||
}
|
|
||||||
return nil, ErrUnsupportedContentType
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSignedData(data []byte) (*PKCS7, error) {
|
|
||||||
var sd signedData
|
|
||||||
asn1.Unmarshal(data, &sd)
|
|
||||||
certs, err := sd.Certificates.Parse()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
|
|
||||||
|
|
||||||
var compound asn1.RawValue
|
|
||||||
var content unsignedData
|
|
||||||
|
|
||||||
// The Content.Bytes maybe empty on PKI responses.
|
|
||||||
if len(sd.ContentInfo.Content.Bytes) > 0 {
|
|
||||||
if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Compound octet string
|
|
||||||
if compound.IsCompound {
|
|
||||||
if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// assuming this is tag 04
|
|
||||||
content = compound.Bytes
|
|
||||||
}
|
|
||||||
return &PKCS7{
|
|
||||||
Content: content,
|
|
||||||
Certificates: certs,
|
|
||||||
CRLs: sd.CRLs,
|
|
||||||
Signers: sd.SignerInfos,
|
|
||||||
raw: sd}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (raw rawCertificates) Parse() ([]*x509.Certificate, error) {
|
|
||||||
if len(raw.Raw) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var val asn1.RawValue
|
|
||||||
if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return x509.ParseCertificates(val.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseEnvelopedData(data []byte) (*PKCS7, error) {
|
|
||||||
var ed envelopedData
|
|
||||||
if _, err := asn1.Unmarshal(data, &ed); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &PKCS7{
|
|
||||||
raw: ed,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify checks the signatures of a PKCS7 object
|
|
||||||
// WARNING: Verify does not check signing time or verify certificate chains at
|
|
||||||
// this time.
|
|
||||||
func (p7 *PKCS7) Verify() (err error) {
|
|
||||||
if len(p7.Signers) == 0 {
|
|
||||||
return errors.New("pkcs7: Message has no signers")
|
|
||||||
}
|
|
||||||
for _, signer := range p7.Signers {
|
|
||||||
if err := verifySignature(p7, signer); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifySignature(p7 *PKCS7, signer signerInfo) error {
|
|
||||||
signedData := p7.Content
|
|
||||||
hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(signer.AuthenticatedAttributes) > 0 {
|
|
||||||
// TODO(fullsailor): First check the content type match
|
|
||||||
var digest []byte
|
|
||||||
err := unmarshalAttribute(signer.AuthenticatedAttributes, oidAttributeMessageDigest, &digest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
h := hash.New()
|
|
||||||
h.Write(p7.Content)
|
|
||||||
computed := h.Sum(nil)
|
|
||||||
if !hmac.Equal(digest, computed) {
|
|
||||||
return &MessageDigestMismatchError{
|
|
||||||
ExpectedDigest: digest,
|
|
||||||
ActualDigest: computed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO(fullsailor): Optionally verify certificate chain
|
|
||||||
// TODO(fullsailor): Optionally verify signingTime against certificate NotAfter/NotBefore
|
|
||||||
signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cert := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
|
||||||
if cert == nil {
|
|
||||||
return errors.New("pkcs7: No certificate for signer")
|
|
||||||
}
|
|
||||||
|
|
||||||
algo := getSignatureAlgorithmFromAI(signer.DigestEncryptionAlgorithm)
|
|
||||||
if algo == x509.UnknownSignatureAlgorithm {
|
|
||||||
// I'm not sure what the spec here is, and the openssl sources were not
|
|
||||||
// helpful. But, this is what App Store receipts appear to do.
|
|
||||||
// The DigestEncryptionAlgorithm is just "rsaEncryption (PKCS #1)"
|
|
||||||
// But we're expecting a digest + encryption algorithm. So... we're going
|
|
||||||
// to determine an algorithm based on the DigestAlgorithm and this
|
|
||||||
// encryption algorithm.
|
|
||||||
if signer.DigestEncryptionAlgorithm.Algorithm.Equal(oidEncryptionAlgorithmRSA) {
|
|
||||||
algo = getRSASignatureAlgorithmForDigestAlgorithm(hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cert.CheckSignature(algo, signedData, signer.EncryptedDigest)
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalAttributes(attrs []attribute) ([]byte, error) {
|
|
||||||
encodedAttributes, err := asn1.Marshal(struct {
|
|
||||||
A []attribute `asn1:"set"`
|
|
||||||
}{A: attrs})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the leading sequence octets
|
|
||||||
var raw asn1.RawValue
|
|
||||||
asn1.Unmarshal(encodedAttributes, &raw)
|
|
||||||
return raw.Bytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
oidDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
|
|
||||||
oidEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
|
||||||
)
|
|
||||||
|
|
||||||
func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
|
|
||||||
for _, cert := range certs {
|
|
||||||
if isCertMatchForIssuerAndSerial(cert, ias) {
|
|
||||||
return cert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
|
|
||||||
switch {
|
|
||||||
case oid.Equal(oidDigestAlgorithmSHA1):
|
|
||||||
return crypto.SHA1, nil
|
|
||||||
case oid.Equal(oidSHA256):
|
|
||||||
return crypto.SHA256, nil
|
|
||||||
}
|
|
||||||
return crypto.Hash(0), ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRSASignatureAlgorithmForDigestAlgorithm(hash crypto.Hash) x509.SignatureAlgorithm {
|
|
||||||
for _, details := range signatureAlgorithmDetails {
|
|
||||||
if details.pubKeyAlgo == x509.RSA && details.hash == hash {
|
|
||||||
return details.algo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOnlySigner returns an x509.Certificate for the first signer of the signed
|
|
||||||
// data payload. If there are more or less than one signer, nil is returned
|
|
||||||
func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
|
|
||||||
if len(p7.Signers) != 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
signer := p7.Signers[0]
|
|
||||||
return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
|
|
||||||
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")
|
|
||||||
|
|
||||||
// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
|
|
||||||
var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type")
|
|
||||||
|
|
||||||
// Decrypt decrypts encrypted content info for recipient cert and private key
|
|
||||||
func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pk crypto.PrivateKey) ([]byte, error) {
|
|
||||||
data, ok := p7.raw.(envelopedData)
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrNotEncryptedContent
|
|
||||||
}
|
|
||||||
recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
|
|
||||||
if recipient.EncryptedKey == nil {
|
|
||||||
return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
|
|
||||||
}
|
|
||||||
if priv := pk.(*rsa.PrivateKey); priv != nil {
|
|
||||||
var contentKey []byte
|
|
||||||
contentKey, err := rsa.DecryptPKCS1v15(rand.Reader, priv, recipient.EncryptedKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return data.EncryptedContentInfo.decrypt(contentKey)
|
|
||||||
}
|
|
||||||
fmt.Printf("Unsupported Private Key: %v\n", pk)
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
var oidEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
|
|
||||||
var oidEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
|
|
||||||
var oidEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
|
||||||
var oidEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
|
|
||||||
var oidEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
|
||||||
|
|
||||||
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
|
|
||||||
alg := eci.ContentEncryptionAlgorithm.Algorithm
|
|
||||||
if !alg.Equal(oidEncryptionAlgorithmDESCBC) &&
|
|
||||||
!alg.Equal(oidEncryptionAlgorithmDESEDE3CBC) &&
|
|
||||||
!alg.Equal(oidEncryptionAlgorithmAES256CBC) &&
|
|
||||||
!alg.Equal(oidEncryptionAlgorithmAES128CBC) &&
|
|
||||||
!alg.Equal(oidEncryptionAlgorithmAES128GCM) {
|
|
||||||
fmt.Printf("Unsupported Content Encryption Algorithm: %s\n", alg)
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncryptedContent can either be constructed of multple OCTET STRINGs
|
|
||||||
// or _be_ a tagged OCTET STRING
|
|
||||||
var cyphertext []byte
|
|
||||||
if eci.EncryptedContent.IsCompound {
|
|
||||||
// Complex case to concat all of the children OCTET STRINGs
|
|
||||||
var buf bytes.Buffer
|
|
||||||
cypherbytes := eci.EncryptedContent.Bytes
|
|
||||||
for {
|
|
||||||
var part []byte
|
|
||||||
cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part)
|
|
||||||
buf.Write(part)
|
|
||||||
if cypherbytes == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cyphertext = buf.Bytes()
|
|
||||||
} else {
|
|
||||||
// Simple case, the bytes _are_ the cyphertext
|
|
||||||
cyphertext = eci.EncryptedContent.Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
var block cipher.Block
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case alg.Equal(oidEncryptionAlgorithmDESCBC):
|
|
||||||
block, err = des.NewCipher(key)
|
|
||||||
case alg.Equal(oidEncryptionAlgorithmDESEDE3CBC):
|
|
||||||
block, err = des.NewTripleDESCipher(key)
|
|
||||||
case alg.Equal(oidEncryptionAlgorithmAES256CBC):
|
|
||||||
fallthrough
|
|
||||||
case alg.Equal(oidEncryptionAlgorithmAES128GCM), alg.Equal(oidEncryptionAlgorithmAES128CBC):
|
|
||||||
block, err = aes.NewCipher(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if alg.Equal(oidEncryptionAlgorithmAES128GCM) {
|
|
||||||
params := aesGCMParameters{}
|
|
||||||
paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
|
||||||
|
|
||||||
_, err := asn1.Unmarshal(paramBytes, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
gcm, err := cipher.NewGCM(block)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params.Nonce) != gcm.NonceSize() {
|
|
||||||
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
|
||||||
}
|
|
||||||
if params.ICVLen != gcm.Overhead() {
|
|
||||||
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return plaintext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
|
||||||
if len(iv) != block.BlockSize() {
|
|
||||||
return nil, errors.New("pkcs7: encryption algorithm parameters are malformed")
|
|
||||||
}
|
|
||||||
mode := cipher.NewCBCDecrypter(block, iv)
|
|
||||||
plaintext := make([]byte, len(cyphertext))
|
|
||||||
mode.CryptBlocks(plaintext, cyphertext)
|
|
||||||
if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return plaintext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo {
|
|
||||||
for _, recp := range recipients {
|
|
||||||
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
|
||||||
return recp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return recipientInfo{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool {
|
|
||||||
return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Compare(cert.RawIssuer, ias.IssuerName.FullBytes) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func pad(data []byte, blocklen int) ([]byte, error) {
|
|
||||||
if blocklen < 1 {
|
|
||||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
|
||||||
}
|
|
||||||
padlen := blocklen - (len(data) % blocklen)
|
|
||||||
if padlen == 0 {
|
|
||||||
padlen = blocklen
|
|
||||||
}
|
|
||||||
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
|
||||||
return append(data, pad...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unpad(data []byte, blocklen int) ([]byte, error) {
|
|
||||||
if blocklen < 1 {
|
|
||||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
|
||||||
}
|
|
||||||
if len(data)%blocklen != 0 || len(data) == 0 {
|
|
||||||
return nil, fmt.Errorf("invalid data len %d", len(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// the last byte is the length of padding
|
|
||||||
padlen := int(data[len(data)-1])
|
|
||||||
|
|
||||||
// check padding integrity, all bytes should be the same
|
|
||||||
pad := data[len(data)-padlen:]
|
|
||||||
for _, padbyte := range pad {
|
|
||||||
if padbyte != byte(padlen) {
|
|
||||||
return nil, errors.New("invalid padding")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data[:len(data)-padlen], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if attr.Type.Equal(attributeType) {
|
|
||||||
_, err := asn1.Unmarshal(attr.Value.Bytes, out)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.New("pkcs7: attribute type not in attributes")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalSignedAttribute decodes a single attribute from the signer info
|
|
||||||
func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
|
|
||||||
sd, ok := p7.raw.(signedData)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("pkcs7: payload is not signedData content")
|
|
||||||
}
|
|
||||||
if len(sd.SignerInfos) < 1 {
|
|
||||||
return errors.New("pkcs7: payload has no signers")
|
|
||||||
}
|
|
||||||
attributes := sd.SignerInfos[0].AuthenticatedAttributes
|
|
||||||
return unmarshalAttribute(attributes, attributeType, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignedData is an opaque data structure for creating signed data payloads
|
|
||||||
type SignedData struct {
|
|
||||||
sd signedData
|
|
||||||
certs []*x509.Certificate
|
|
||||||
messageDigest []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attribute represents a key value pair attribute. Value must be marshalable byte
|
|
||||||
// `encoding/asn1`
|
|
||||||
type Attribute struct {
|
|
||||||
Type asn1.ObjectIdentifier
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignerInfoConfig are optional values to include when adding a signer
|
|
||||||
type SignerInfoConfig struct {
|
|
||||||
ExtraSignedAttributes []Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSignedData initializes a SignedData with content
|
|
||||||
func NewSignedData(data []byte) (*SignedData, error) {
|
|
||||||
content, err := asn1.Marshal(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ci := contentInfo{
|
|
||||||
ContentType: oidData,
|
|
||||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
|
||||||
}
|
|
||||||
digAlg := pkix.AlgorithmIdentifier{
|
|
||||||
Algorithm: oidDigestAlgorithmSHA1,
|
|
||||||
}
|
|
||||||
h := crypto.SHA1.New()
|
|
||||||
h.Write(data)
|
|
||||||
md := h.Sum(nil)
|
|
||||||
sd := signedData{
|
|
||||||
ContentInfo: ci,
|
|
||||||
Version: 1,
|
|
||||||
DigestAlgorithmIdentifiers: []pkix.AlgorithmIdentifier{digAlg},
|
|
||||||
}
|
|
||||||
return &SignedData{sd: sd, messageDigest: md}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type attributes struct {
|
|
||||||
types []asn1.ObjectIdentifier
|
|
||||||
values []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds the attribute, maintaining insertion order
|
|
||||||
func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) {
|
|
||||||
attrs.types = append(attrs.types, attrType)
|
|
||||||
attrs.values = append(attrs.values, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortableAttribute struct {
|
|
||||||
SortKey []byte
|
|
||||||
Attribute attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
type attributeSet []sortableAttribute
|
|
||||||
|
|
||||||
func (sa attributeSet) Len() int {
|
|
||||||
return len(sa)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sa attributeSet) Less(i, j int) bool {
|
|
||||||
return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sa attributeSet) Swap(i, j int) {
|
|
||||||
sa[i], sa[j] = sa[j], sa[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sa attributeSet) Attributes() []attribute {
|
|
||||||
attrs := make([]attribute, len(sa))
|
|
||||||
for i, attr := range sa {
|
|
||||||
attrs[i] = attr.Attribute
|
|
||||||
}
|
|
||||||
return attrs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (attrs *attributes) ForMarshaling() ([]attribute, error) {
|
|
||||||
sortables := make(attributeSet, len(attrs.types))
|
|
||||||
for i := range sortables {
|
|
||||||
attrType := attrs.types[i]
|
|
||||||
attrValue := attrs.values[i]
|
|
||||||
asn1Value, err := asn1.Marshal(attrValue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
attr := attribute{
|
|
||||||
Type: attrType,
|
|
||||||
Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag
|
|
||||||
}
|
|
||||||
encoded, err := asn1.Marshal(attr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sortables[i] = sortableAttribute{
|
|
||||||
SortKey: encoded,
|
|
||||||
Attribute: attr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(sortables)
|
|
||||||
return sortables.Attributes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSigner signs attributes about the content and adds certificate to payload
|
|
||||||
func (sd *SignedData) AddSigner(cert *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
|
|
||||||
attrs := &attributes{}
|
|
||||||
attrs.Add(oidAttributeContentType, sd.sd.ContentInfo.ContentType)
|
|
||||||
attrs.Add(oidAttributeMessageDigest, sd.messageDigest)
|
|
||||||
attrs.Add(oidAttributeSigningTime, time.Now())
|
|
||||||
for _, attr := range config.ExtraSignedAttributes {
|
|
||||||
attrs.Add(attr.Type, attr.Value)
|
|
||||||
}
|
|
||||||
finalAttrs, err := attrs.ForMarshaling()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
signature, err := signAttributes(finalAttrs, pkey, crypto.SHA1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ias, err := cert2issuerAndSerial(cert)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
signer := signerInfo{
|
|
||||||
AuthenticatedAttributes: finalAttrs,
|
|
||||||
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidDigestAlgorithmSHA1},
|
|
||||||
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSignatureSHA1WithRSA},
|
|
||||||
IssuerAndSerialNumber: ias,
|
|
||||||
EncryptedDigest: signature,
|
|
||||||
Version: 1,
|
|
||||||
}
|
|
||||||
// create signature of signed attributes
|
|
||||||
sd.certs = append(sd.certs, cert)
|
|
||||||
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddCertificate adds the certificate to the payload. Useful for parent certificates
|
|
||||||
func (sd *SignedData) AddCertificate(cert *x509.Certificate) {
|
|
||||||
sd.certs = append(sd.certs, cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detach removes content from the signed data struct to make it a detached signature.
|
|
||||||
// This must be called right before Finish()
|
|
||||||
func (sd *SignedData) Detach() {
|
|
||||||
sd.sd.ContentInfo = contentInfo{ContentType: oidData}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finish marshals the content and its signers
|
|
||||||
func (sd *SignedData) Finish() ([]byte, error) {
|
|
||||||
sd.sd.Certificates = marshalCertificates(sd.certs)
|
|
||||||
inner, err := asn1.Marshal(sd.sd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
outer := contentInfo{
|
|
||||||
ContentType: oidSignedData,
|
|
||||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: inner, IsCompound: true},
|
|
||||||
}
|
|
||||||
return asn1.Marshal(outer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cert2issuerAndSerial(cert *x509.Certificate) (issuerAndSerial, error) {
|
|
||||||
var ias issuerAndSerial
|
|
||||||
// The issuer RDNSequence has to match exactly the sequence in the certificate
|
|
||||||
// We cannot use cert.Issuer.ToRDNSequence() here since it mangles the sequence
|
|
||||||
ias.IssuerName = asn1.RawValue{FullBytes: cert.RawIssuer}
|
|
||||||
ias.SerialNumber = cert.SerialNumber
|
|
||||||
|
|
||||||
return ias, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// signs the DER encoded form of the attributes with the private key
|
|
||||||
func signAttributes(attrs []attribute, pkey crypto.PrivateKey, hash crypto.Hash) ([]byte, error) {
|
|
||||||
attrBytes, err := marshalAttributes(attrs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
h := hash.New()
|
|
||||||
h.Write(attrBytes)
|
|
||||||
hashed := h.Sum(nil)
|
|
||||||
switch priv := pkey.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
return rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA1, hashed)
|
|
||||||
}
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// concats and wraps the certificates in the RawValue structure
|
|
||||||
func marshalCertificates(certs []*x509.Certificate) rawCertificates {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, cert := range certs {
|
|
||||||
buf.Write(cert.Raw)
|
|
||||||
}
|
|
||||||
rawCerts, _ := marshalCertificateBytes(buf.Bytes())
|
|
||||||
return rawCerts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even though, the tag & length are stripped out during marshalling the
|
|
||||||
// RawContent, we have to encode it into the RawContent. If its missing,
|
|
||||||
// then `asn1.Marshal()` will strip out the certificate wrapper instead.
|
|
||||||
func marshalCertificateBytes(certs []byte) (rawCertificates, error) {
|
|
||||||
var val = asn1.RawValue{Bytes: certs, Class: 2, Tag: 0, IsCompound: true}
|
|
||||||
b, err := asn1.Marshal(val)
|
|
||||||
if err != nil {
|
|
||||||
return rawCertificates{}, err
|
|
||||||
}
|
|
||||||
return rawCertificates{Raw: b}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DegenerateCertificate creates a signed data structure containing only the
|
|
||||||
// provided certificate or certificate chain.
|
|
||||||
func DegenerateCertificate(cert []byte) ([]byte, error) {
|
|
||||||
rawCert, err := marshalCertificateBytes(cert)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
emptyContent := contentInfo{ContentType: oidData}
|
|
||||||
sd := signedData{
|
|
||||||
Version: 1,
|
|
||||||
ContentInfo: emptyContent,
|
|
||||||
Certificates: rawCert,
|
|
||||||
CRLs: []pkix.CertificateList{},
|
|
||||||
}
|
|
||||||
content, err := asn1.Marshal(sd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signedContent := contentInfo{
|
|
||||||
ContentType: oidSignedData,
|
|
||||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
|
||||||
}
|
|
||||||
return asn1.Marshal(signedContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
EncryptionAlgorithmDESCBC = iota
|
|
||||||
EncryptionAlgorithmAES128GCM
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
|
||||||
// plaintext message. Change the value of this variable to change which
|
|
||||||
// algorithm is used in the Encrypt() function.
|
|
||||||
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC
|
|
||||||
|
|
||||||
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
|
||||||
// content with an unsupported algorithm.
|
|
||||||
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC and AES-128-GCM supported")
|
|
||||||
|
|
||||||
const nonceSize = 12
|
|
||||||
|
|
||||||
type aesGCMParameters struct {
|
|
||||||
Nonce []byte `asn1:"tag:4"`
|
|
||||||
ICVLen int
|
|
||||||
}
|
|
||||||
|
|
||||||
func encryptAES128GCM(content []byte) ([]byte, *encryptedContentInfo, error) {
|
|
||||||
// Create AES key and nonce
|
|
||||||
key := make([]byte, 16)
|
|
||||||
nonce := make([]byte, nonceSize)
|
|
||||||
|
|
||||||
_, err := rand.Read(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = rand.Read(nonce)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt content
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
gcm, err := cipher.NewGCM(block)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ciphertext := gcm.Seal(nil, nonce, content, nil)
|
|
||||||
|
|
||||||
// Prepare ASN.1 Encrypted Content Info
|
|
||||||
paramSeq := aesGCMParameters{
|
|
||||||
Nonce: nonce,
|
|
||||||
ICVLen: gcm.Overhead(),
|
|
||||||
}
|
|
||||||
|
|
||||||
paramBytes, err := asn1.Marshal(paramSeq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
eci := encryptedContentInfo{
|
|
||||||
ContentType: oidData,
|
|
||||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
|
||||||
Algorithm: oidEncryptionAlgorithmAES128GCM,
|
|
||||||
Parameters: asn1.RawValue{
|
|
||||||
Tag: asn1.TagSequence,
|
|
||||||
Bytes: paramBytes,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
|
||||||
}
|
|
||||||
|
|
||||||
return key, &eci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func encryptDESCBC(content []byte) ([]byte, *encryptedContentInfo, error) {
|
|
||||||
// Create DES key & CBC IV
|
|
||||||
key := make([]byte, 8)
|
|
||||||
iv := make([]byte, des.BlockSize)
|
|
||||||
_, err := rand.Read(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
_, err = rand.Read(iv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt padded content
|
|
||||||
block, err := des.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
mode := cipher.NewCBCEncrypter(block, iv)
|
|
||||||
plaintext, err := pad(content, mode.BlockSize())
|
|
||||||
cyphertext := make([]byte, len(plaintext))
|
|
||||||
mode.CryptBlocks(cyphertext, plaintext)
|
|
||||||
|
|
||||||
// Prepare ASN.1 Encrypted Content Info
|
|
||||||
eci := encryptedContentInfo{
|
|
||||||
ContentType: oidData,
|
|
||||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
|
||||||
Algorithm: oidEncryptionAlgorithmDESCBC,
|
|
||||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
|
||||||
},
|
|
||||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
|
||||||
}
|
|
||||||
|
|
||||||
return key, &eci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
|
||||||
// recipient keys for each recipient public key.
|
|
||||||
//
|
|
||||||
// The algorithm used to perform encryption is determined by the current value
|
|
||||||
// of the global ContentEncryptionAlgorithm package variable. By default, the
|
|
||||||
// value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the
|
|
||||||
// value before calling Encrypt(). For example:
|
|
||||||
//
|
|
||||||
// ContentEncryptionAlgorithm = EncryptionAlgorithmAES128GCM
|
|
||||||
//
|
|
||||||
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
|
||||||
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
|
|
||||||
var eci *encryptedContentInfo
|
|
||||||
var key []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Apply chosen symmetric encryption method
|
|
||||||
switch ContentEncryptionAlgorithm {
|
|
||||||
case EncryptionAlgorithmDESCBC:
|
|
||||||
key, eci, err = encryptDESCBC(content)
|
|
||||||
|
|
||||||
case EncryptionAlgorithmAES128GCM:
|
|
||||||
key, eci, err = encryptAES128GCM(content)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare each recipient's encrypted cipher key
|
|
||||||
recipientInfos := make([]recipientInfo, len(recipients))
|
|
||||||
for i, recipient := range recipients {
|
|
||||||
encrypted, err := encryptKey(key, recipient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ias, err := cert2issuerAndSerial(recipient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
info := recipientInfo{
|
|
||||||
Version: 0,
|
|
||||||
IssuerAndSerialNumber: ias,
|
|
||||||
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
|
||||||
Algorithm: oidEncryptionAlgorithmRSA,
|
|
||||||
},
|
|
||||||
EncryptedKey: encrypted,
|
|
||||||
}
|
|
||||||
recipientInfos[i] = info
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare envelope content
|
|
||||||
envelope := envelopedData{
|
|
||||||
EncryptedContentInfo: *eci,
|
|
||||||
Version: 0,
|
|
||||||
RecipientInfos: recipientInfos,
|
|
||||||
}
|
|
||||||
innerContent, err := asn1.Marshal(envelope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare outer payload structure
|
|
||||||
wrapper := contentInfo{
|
|
||||||
ContentType: oidEnvelopedData,
|
|
||||||
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
|
||||||
}
|
|
||||||
|
|
||||||
return asn1.Marshal(wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
|
||||||
asn1Content, _ := asn1.Marshal(content)
|
|
||||||
return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
|
||||||
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
|
||||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
|
||||||
}
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
133
vendor/github.com/fullsailor/pkcs7/x509.go
generated
vendored
133
vendor/github.com/fullsailor/pkcs7/x509.go
generated
vendored
@@ -1,133 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the go/golang LICENSE file.
|
|
||||||
|
|
||||||
package pkcs7
|
|
||||||
|
|
||||||
// These are private constants and functions from the crypto/x509 package that
|
|
||||||
// are useful when dealing with signatures verified by x509 certificates
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto"
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/asn1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
|
||||||
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
|
||||||
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
|
||||||
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
|
||||||
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
|
||||||
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
|
||||||
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
|
||||||
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
|
||||||
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
|
|
||||||
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
|
||||||
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
|
||||||
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
|
||||||
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
|
||||||
|
|
||||||
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
|
||||||
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
|
||||||
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
|
||||||
|
|
||||||
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
|
||||||
|
|
||||||
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
|
|
||||||
// but it's specified by ISO. Microsoft's makecert.exe has been known
|
|
||||||
// to produce certificates with this OID.
|
|
||||||
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
|
||||||
)
|
|
||||||
|
|
||||||
var signatureAlgorithmDetails = []struct {
|
|
||||||
algo x509.SignatureAlgorithm
|
|
||||||
name string
|
|
||||||
oid asn1.ObjectIdentifier
|
|
||||||
pubKeyAlgo x509.PublicKeyAlgorithm
|
|
||||||
hash crypto.Hash
|
|
||||||
}{
|
|
||||||
{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
|
|
||||||
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
|
|
||||||
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
|
||||||
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
|
||||||
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
|
|
||||||
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
|
|
||||||
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
|
|
||||||
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
|
|
||||||
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
|
|
||||||
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
|
|
||||||
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
|
|
||||||
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
|
|
||||||
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
|
|
||||||
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
|
|
||||||
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
|
|
||||||
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
|
|
||||||
}
|
|
||||||
|
|
||||||
// pssParameters reflects the parameters in an AlgorithmIdentifier that
|
|
||||||
// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
|
|
||||||
type pssParameters struct {
|
|
||||||
// The following three fields are not marked as
|
|
||||||
// optional because the default values specify SHA-1,
|
|
||||||
// which is no longer suitable for use in signatures.
|
|
||||||
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
|
|
||||||
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
|
|
||||||
SaltLength int `asn1:"explicit,tag:2"`
|
|
||||||
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// asn1.NullBytes is not available prior to Go 1.9
|
|
||||||
var nullBytes = []byte{5, 0}
|
|
||||||
|
|
||||||
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm {
|
|
||||||
if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
|
|
||||||
for _, details := range signatureAlgorithmDetails {
|
|
||||||
if ai.Algorithm.Equal(details.oid) {
|
|
||||||
return details.algo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// RSA PSS is special because it encodes important parameters
|
|
||||||
// in the Parameters.
|
|
||||||
|
|
||||||
var params pssParameters
|
|
||||||
if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil {
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
var mgf1HashFunc pkix.AlgorithmIdentifier
|
|
||||||
if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSS is greatly overburdened with options. This code forces
|
|
||||||
// them into three buckets by requiring that the MGF1 hash
|
|
||||||
// function always match the message hash function (as
|
|
||||||
// recommended in
|
|
||||||
// https://tools.ietf.org/html/rfc3447#section-8.1), that the
|
|
||||||
// salt length matches the hash length, and that the trailer
|
|
||||||
// field has the default value.
|
|
||||||
if !bytes.Equal(params.Hash.Parameters.FullBytes, nullBytes) ||
|
|
||||||
!params.MGF.Algorithm.Equal(oidMGF1) ||
|
|
||||||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
|
|
||||||
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, nullBytes) ||
|
|
||||||
params.TrailerField != 1 {
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
|
|
||||||
return x509.SHA256WithRSAPSS
|
|
||||||
case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
|
|
||||||
return x509.SHA384WithRSAPSS
|
|
||||||
case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
|
|
||||||
return x509.SHA512WithRSAPSS
|
|
||||||
}
|
|
||||||
|
|
||||||
return x509.UnknownSignatureAlgorithm
|
|
||||||
}
|
|
10
vendor/go.mozilla.org/pkcs7/.travis.yml
generated
vendored
Normal file
10
vendor/go.mozilla.org/pkcs7/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.11"
|
||||||
|
- "1.12"
|
||||||
|
- "1.13"
|
||||||
|
- tip
|
||||||
|
before_install:
|
||||||
|
- make gettools
|
||||||
|
script:
|
||||||
|
- make
|
0
vendor/github.com/fullsailor/pkcs7/LICENSE → vendor/go.mozilla.org/pkcs7/LICENSE
generated
vendored
0
vendor/github.com/fullsailor/pkcs7/LICENSE → vendor/go.mozilla.org/pkcs7/LICENSE
generated
vendored
20
vendor/go.mozilla.org/pkcs7/Makefile
generated
vendored
Normal file
20
vendor/go.mozilla.org/pkcs7/Makefile
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
all: vet staticcheck test
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -covermode=count -coverprofile=coverage.out .
|
||||||
|
|
||||||
|
showcoverage: test
|
||||||
|
go tool cover -html=coverage.out
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet .
|
||||||
|
|
||||||
|
lint:
|
||||||
|
golint .
|
||||||
|
|
||||||
|
staticcheck:
|
||||||
|
staticcheck .
|
||||||
|
|
||||||
|
gettools:
|
||||||
|
go get -u honnef.co/go/tools/...
|
||||||
|
go get -u golang.org/x/lint/golint
|
69
vendor/go.mozilla.org/pkcs7/README.md
generated
vendored
Normal file
69
vendor/go.mozilla.org/pkcs7/README.md
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# pkcs7
|
||||||
|
|
||||||
|
[](https://godoc.org/go.mozilla.org/pkcs7)
|
||||||
|
[](https://travis-ci.org/mozilla-services/pkcs7)
|
||||||
|
|
||||||
|
pkcs7 implements parsing and creating signed and enveloped messages.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"go.mozilla.org/pkcs7"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) {
|
||||||
|
toBeSigned, err := NewSignedData(content)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Cannot initialize signed data: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil {
|
||||||
|
err = fmt.Errorf("Cannot add signer: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach signature, omit if you want an embedded signature
|
||||||
|
toBeSigned.Detach()
|
||||||
|
|
||||||
|
signed, err = toBeSigned.Finish()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Cannot finish signing data: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed})
|
||||||
|
p7, err := pkcs7.Parse(signed)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Cannot parse our signed data: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// since the signature was detached, reattach the content here
|
||||||
|
p7.Content = content
|
||||||
|
|
||||||
|
if bytes.Compare(content, p7.Content) != 0 {
|
||||||
|
err = fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = p7.Verify(); err != nil {
|
||||||
|
err = fmt.Errorf("Cannot verify our signed data: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return signed, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
This is a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7)
|
101
vendor/github.com/fullsailor/pkcs7/ber.go → vendor/go.mozilla.org/pkcs7/ber.go
generated
vendored
101
vendor/github.com/fullsailor/pkcs7/ber.go → vendor/go.mozilla.org/pkcs7/ber.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// var encodeIndent = 0
|
var encodeIndent = 0
|
||||||
|
|
||||||
type asn1Object interface {
|
type asn1Object interface {
|
||||||
EncodeTo(writer *bytes.Buffer) error
|
EncodeTo(writer *bytes.Buffer) error
|
||||||
@@ -18,7 +18,7 @@ type asn1Structured struct {
|
|||||||
|
|
||||||
func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
||||||
//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
|
//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
|
||||||
//encodeIndent++
|
encodeIndent++
|
||||||
inner := new(bytes.Buffer)
|
inner := new(bytes.Buffer)
|
||||||
for _, obj := range s.content {
|
for _, obj := range s.content {
|
||||||
err := obj.EncodeTo(inner)
|
err := obj.EncodeTo(inner)
|
||||||
@@ -26,7 +26,7 @@ func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//encodeIndent--
|
encodeIndent--
|
||||||
out.Write(s.tagBytes)
|
out.Write(s.tagBytes)
|
||||||
encodeLength(out, inner.Len())
|
encodeLength(out, inner.Len())
|
||||||
out.Write(inner.Bytes())
|
out.Write(inner.Bytes())
|
||||||
@@ -133,35 +133,49 @@ func encodeLength(out *bytes.Buffer, length int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
||||||
//fmt.Printf("\n====> Starting readObject at offset: %d\n\n", offset)
|
berLen := len(ber)
|
||||||
|
if offset >= berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: offset is after end of ber data")
|
||||||
|
}
|
||||||
tagStart := offset
|
tagStart := offset
|
||||||
b := ber[offset]
|
b := ber[offset]
|
||||||
offset++
|
offset++
|
||||||
|
if offset >= berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||||
|
}
|
||||||
tag := b & 0x1F // last 5 bits
|
tag := b & 0x1F // last 5 bits
|
||||||
if tag == 0x1F {
|
if tag == 0x1F {
|
||||||
tag = 0
|
tag = 0
|
||||||
for ber[offset] >= 0x80 {
|
for ber[offset] >= 0x80 {
|
||||||
tag = tag*128 + ber[offset] - 0x80
|
tag = tag*128 + ber[offset] - 0x80
|
||||||
offset++
|
offset++
|
||||||
|
if offset > berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tag = tag*128 + ber[offset] - 0x80
|
// jvehent 20170227: this doesn't appear to be used anywhere...
|
||||||
|
//tag = tag*128 + ber[offset] - 0x80
|
||||||
offset++
|
offset++
|
||||||
|
if offset > berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tagEnd := offset
|
tagEnd := offset
|
||||||
|
|
||||||
kind := b & 0x20
|
kind := b & 0x20
|
||||||
/*
|
if kind == 0 {
|
||||||
if kind == 0 {
|
debugprint("--> Primitive\n")
|
||||||
fmt.Print("--> Primitive\n")
|
} else {
|
||||||
} else {
|
debugprint("--> Constructed\n")
|
||||||
fmt.Print("--> Constructed\n")
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
// read length
|
// read length
|
||||||
var length int
|
var length int
|
||||||
l := ber[offset]
|
l := ber[offset]
|
||||||
offset++
|
offset++
|
||||||
indefinite := false
|
if offset > berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||||
|
}
|
||||||
|
hack := 0
|
||||||
if l > 0x80 {
|
if l > 0x80 {
|
||||||
numberOfBytes := (int)(l & 0x7F)
|
numberOfBytes := (int)(l & 0x7F)
|
||||||
if numberOfBytes > 4 { // int is only guaranteed to be 32bit
|
if numberOfBytes > 4 { // int is only guaranteed to be 32bit
|
||||||
@@ -170,33 +184,42 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
|||||||
if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
|
if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
|
||||||
return nil, 0, errors.New("ber2der: BER tag length is negative")
|
return nil, 0, errors.New("ber2der: BER tag length is negative")
|
||||||
}
|
}
|
||||||
if 0x0 == (int)(ber[offset]) {
|
if (int)(ber[offset]) == 0x0 {
|
||||||
return nil, 0, errors.New("ber2der: BER tag length has leading zero")
|
return nil, 0, errors.New("ber2der: BER tag length has leading zero")
|
||||||
}
|
}
|
||||||
//fmt.Printf("--> (compute length) indicator byte: %x\n", l)
|
debugprint("--> (compute length) indicator byte: %x\n", l)
|
||||||
//fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
|
debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
|
||||||
for i := 0; i < numberOfBytes; i++ {
|
for i := 0; i < numberOfBytes; i++ {
|
||||||
length = length*256 + (int)(ber[offset])
|
length = length*256 + (int)(ber[offset])
|
||||||
offset++
|
offset++
|
||||||
|
if offset > berLen {
|
||||||
|
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if l == 0x80 {
|
} else if l == 0x80 {
|
||||||
indefinite = true
|
// find length by searching content
|
||||||
|
markerIndex := bytes.LastIndex(ber[offset:], []byte{0x0, 0x0})
|
||||||
|
if markerIndex == -1 {
|
||||||
|
return nil, 0, errors.New("ber2der: Invalid BER format")
|
||||||
|
}
|
||||||
|
length = markerIndex
|
||||||
|
hack = 2
|
||||||
|
debugprint("--> (compute length) marker found at offset: %d\n", markerIndex+offset)
|
||||||
} else {
|
} else {
|
||||||
length = (int)(l)
|
length = (int)(l)
|
||||||
}
|
}
|
||||||
|
if length < 0 {
|
||||||
|
return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length")
|
||||||
|
}
|
||||||
//fmt.Printf("--> length : %d\n", length)
|
//fmt.Printf("--> length : %d\n", length)
|
||||||
contentEnd := offset + length
|
contentEnd := offset + length
|
||||||
if contentEnd > len(ber) {
|
if contentEnd > len(ber) {
|
||||||
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
|
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
|
||||||
}
|
}
|
||||||
//fmt.Printf("--> content start : %d\n", offset)
|
debugprint("--> content start : %d\n", offset)
|
||||||
//fmt.Printf("--> content end : %d\n", contentEnd)
|
debugprint("--> content end : %d\n", contentEnd)
|
||||||
//fmt.Printf("--> content : % X\n", ber[offset:contentEnd])
|
debugprint("--> content : % X\n", ber[offset:contentEnd])
|
||||||
var obj asn1Object
|
var obj asn1Object
|
||||||
if indefinite && kind == 0 {
|
|
||||||
return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
|
|
||||||
}
|
|
||||||
if kind == 0 {
|
if kind == 0 {
|
||||||
obj = asn1Primitive{
|
obj = asn1Primitive{
|
||||||
tagBytes: ber[tagStart:tagEnd],
|
tagBytes: ber[tagStart:tagEnd],
|
||||||
@@ -205,25 +228,14 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var subObjects []asn1Object
|
var subObjects []asn1Object
|
||||||
for (offset < contentEnd) || indefinite {
|
for offset < contentEnd {
|
||||||
var subObj asn1Object
|
var subObj asn1Object
|
||||||
var err error
|
var err error
|
||||||
subObj, offset, err = readObject(ber, offset)
|
subObj, offset, err = readObject(ber[:contentEnd], offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
subObjects = append(subObjects, subObj)
|
subObjects = append(subObjects, subObj)
|
||||||
|
|
||||||
if indefinite {
|
|
||||||
terminated, err := isIndefiniteTermination(ber, offset)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if terminated {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
obj = asn1Structured{
|
obj = asn1Structured{
|
||||||
tagBytes: ber[tagStart:tagEnd],
|
tagBytes: ber[tagStart:tagEnd],
|
||||||
@@ -231,18 +243,9 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply indefinite form length with 0x0000 terminator.
|
return obj, contentEnd + hack, nil
|
||||||
if indefinite {
|
|
||||||
contentEnd = offset + 2
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj, contentEnd, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
|
func debugprint(format string, a ...interface{}) {
|
||||||
if len(ber) - offset < 2 {
|
//fmt.Printf(format, a)
|
||||||
return false, errors.New("ber2der: Invalid BER format")
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
|
|
||||||
}
|
}
|
177
vendor/go.mozilla.org/pkcs7/decrypt.go
generated
vendored
Normal file
177
vendor/go.mozilla.org/pkcs7/decrypt.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
|
||||||
|
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")
|
||||||
|
|
||||||
|
// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
|
||||||
|
var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type")
|
||||||
|
|
||||||
|
// Decrypt decrypts encrypted content info for recipient cert and private key
|
||||||
|
func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
|
||||||
|
data, ok := p7.raw.(envelopedData)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotEncryptedContent
|
||||||
|
}
|
||||||
|
recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
|
||||||
|
if recipient.EncryptedKey == nil {
|
||||||
|
return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
|
||||||
|
}
|
||||||
|
switch pkey := pkey.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
var contentKey []byte
|
||||||
|
contentKey, err := rsa.DecryptPKCS1v15(rand.Reader, pkey, recipient.EncryptedKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data.EncryptedContentInfo.decrypt(contentKey)
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptUsingPSK decrypts encrypted data using caller provided
|
||||||
|
// pre-shared secret
|
||||||
|
func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) {
|
||||||
|
data, ok := p7.raw.(encryptedData)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotEncryptedContent
|
||||||
|
}
|
||||||
|
return data.EncryptedContentInfo.decrypt(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
|
||||||
|
alg := eci.ContentEncryptionAlgorithm.Algorithm
|
||||||
|
if !alg.Equal(OIDEncryptionAlgorithmDESCBC) &&
|
||||||
|
!alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC) &&
|
||||||
|
!alg.Equal(OIDEncryptionAlgorithmAES256CBC) &&
|
||||||
|
!alg.Equal(OIDEncryptionAlgorithmAES128CBC) &&
|
||||||
|
!alg.Equal(OIDEncryptionAlgorithmAES128GCM) &&
|
||||||
|
!alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
|
||||||
|
fmt.Printf("Unsupported Content Encryption Algorithm: %s\n", alg)
|
||||||
|
return nil, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptedContent can either be constructed of multple OCTET STRINGs
|
||||||
|
// or _be_ a tagged OCTET STRING
|
||||||
|
var cyphertext []byte
|
||||||
|
if eci.EncryptedContent.IsCompound {
|
||||||
|
// Complex case to concat all of the children OCTET STRINGs
|
||||||
|
var buf bytes.Buffer
|
||||||
|
cypherbytes := eci.EncryptedContent.Bytes
|
||||||
|
for {
|
||||||
|
var part []byte
|
||||||
|
cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part)
|
||||||
|
buf.Write(part)
|
||||||
|
if cypherbytes == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cyphertext = buf.Bytes()
|
||||||
|
} else {
|
||||||
|
// Simple case, the bytes _are_ the cyphertext
|
||||||
|
cyphertext = eci.EncryptedContent.Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
var block cipher.Block
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case alg.Equal(OIDEncryptionAlgorithmDESCBC):
|
||||||
|
block, err = des.NewCipher(key)
|
||||||
|
case alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC):
|
||||||
|
block, err = des.NewTripleDESCipher(key)
|
||||||
|
case alg.Equal(OIDEncryptionAlgorithmAES256CBC), alg.Equal(OIDEncryptionAlgorithmAES256GCM):
|
||||||
|
fallthrough
|
||||||
|
case alg.Equal(OIDEncryptionAlgorithmAES128GCM), alg.Equal(OIDEncryptionAlgorithmAES128CBC):
|
||||||
|
block, err = aes.NewCipher(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if alg.Equal(OIDEncryptionAlgorithmAES128GCM) || alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
|
||||||
|
params := aesGCMParameters{}
|
||||||
|
paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
||||||
|
|
||||||
|
_, err := asn1.Unmarshal(paramBytes, ¶ms)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.Nonce) != gcm.NonceSize() {
|
||||||
|
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
||||||
|
}
|
||||||
|
if params.ICVLen != gcm.Overhead() {
|
||||||
|
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
||||||
|
if len(iv) != block.BlockSize() {
|
||||||
|
return nil, errors.New("pkcs7: encryption algorithm parameters are malformed")
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
plaintext := make([]byte, len(cyphertext))
|
||||||
|
mode.CryptBlocks(plaintext, cyphertext)
|
||||||
|
if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return plaintext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpad(data []byte, blocklen int) ([]byte, error) {
|
||||||
|
if blocklen < 1 {
|
||||||
|
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||||
|
}
|
||||||
|
if len(data)%blocklen != 0 || len(data) == 0 {
|
||||||
|
return nil, fmt.Errorf("invalid data len %d", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// the last byte is the length of padding
|
||||||
|
padlen := int(data[len(data)-1])
|
||||||
|
|
||||||
|
// check padding integrity, all bytes should be the same
|
||||||
|
pad := data[len(data)-padlen:]
|
||||||
|
for _, padbyte := range pad {
|
||||||
|
if padbyte != byte(padlen) {
|
||||||
|
return nil, errors.New("invalid padding")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data[:len(data)-padlen], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo {
|
||||||
|
for _, recp := range recipients {
|
||||||
|
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
||||||
|
return recp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recipientInfo{}
|
||||||
|
}
|
399
vendor/go.mozilla.org/pkcs7/encrypt.go
generated
vendored
Normal file
399
vendor/go.mozilla.org/pkcs7/encrypt.go
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type envelopedData struct {
|
||||||
|
Version int
|
||||||
|
RecipientInfos []recipientInfo `asn1:"set"`
|
||||||
|
EncryptedContentInfo encryptedContentInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type encryptedData struct {
|
||||||
|
Version int
|
||||||
|
EncryptedContentInfo encryptedContentInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type recipientInfo struct {
|
||||||
|
Version int
|
||||||
|
IssuerAndSerialNumber issuerAndSerial
|
||||||
|
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
EncryptedKey []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type encryptedContentInfo struct {
|
||||||
|
ContentType asn1.ObjectIdentifier
|
||||||
|
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
EncryptedContent asn1.RawValue `asn1:"tag:0,optional,explicit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EncryptionAlgorithmDESCBC is the DES CBC encryption algorithm
|
||||||
|
EncryptionAlgorithmDESCBC = iota
|
||||||
|
|
||||||
|
// EncryptionAlgorithmAES128CBC is the AES 128 bits with CBC encryption algorithm
|
||||||
|
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||||
|
EncryptionAlgorithmAES128CBC
|
||||||
|
|
||||||
|
// EncryptionAlgorithmAES256CBC is the AES 256 bits with CBC encryption algorithm
|
||||||
|
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||||
|
EncryptionAlgorithmAES256CBC
|
||||||
|
|
||||||
|
// EncryptionAlgorithmAES128GCM is the AES 128 bits with GCM encryption algorithm
|
||||||
|
EncryptionAlgorithmAES128GCM
|
||||||
|
|
||||||
|
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
|
||||||
|
EncryptionAlgorithmAES256GCM
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
||||||
|
// plaintext message. Change the value of this variable to change which
|
||||||
|
// algorithm is used in the Encrypt() function.
|
||||||
|
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC
|
||||||
|
|
||||||
|
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
||||||
|
// content with an unsupported algorithm.
|
||||||
|
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, and AES-GCM supported")
|
||||||
|
|
||||||
|
// ErrPSKNotProvided is returned when attempting to encrypt
|
||||||
|
// using a PSK without actually providing the PSK.
|
||||||
|
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")
|
||||||
|
|
||||||
|
const nonceSize = 12
|
||||||
|
|
||||||
|
type aesGCMParameters struct {
|
||||||
|
Nonce []byte `asn1:"tag:4"`
|
||||||
|
ICVLen int
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||||
|
var keyLen int
|
||||||
|
var algID asn1.ObjectIdentifier
|
||||||
|
switch ContentEncryptionAlgorithm {
|
||||||
|
case EncryptionAlgorithmAES128GCM:
|
||||||
|
keyLen = 16
|
||||||
|
algID = OIDEncryptionAlgorithmAES128GCM
|
||||||
|
case EncryptionAlgorithmAES256GCM:
|
||||||
|
keyLen = 32
|
||||||
|
algID = OIDEncryptionAlgorithmAES256GCM
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", ContentEncryptionAlgorithm)
|
||||||
|
}
|
||||||
|
if key == nil {
|
||||||
|
// Create AES key
|
||||||
|
key = make([]byte, keyLen)
|
||||||
|
|
||||||
|
_, err := rand.Read(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create nonce
|
||||||
|
nonce := make([]byte, nonceSize)
|
||||||
|
|
||||||
|
_, err := rand.Read(nonce)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt content
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gcm, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ciphertext := gcm.Seal(nil, nonce, content, nil)
|
||||||
|
|
||||||
|
// Prepare ASN.1 Encrypted Content Info
|
||||||
|
paramSeq := aesGCMParameters{
|
||||||
|
Nonce: nonce,
|
||||||
|
ICVLen: gcm.Overhead(),
|
||||||
|
}
|
||||||
|
|
||||||
|
paramBytes, err := asn1.Marshal(paramSeq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eci := encryptedContentInfo{
|
||||||
|
ContentType: OIDData,
|
||||||
|
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: algID,
|
||||||
|
Parameters: asn1.RawValue{
|
||||||
|
Tag: asn1.TagSequence,
|
||||||
|
Bytes: paramBytes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EncryptedContent: marshalEncryptedContent(ciphertext),
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, &eci, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||||
|
if key == nil {
|
||||||
|
// Create DES key
|
||||||
|
key = make([]byte, 8)
|
||||||
|
|
||||||
|
_, err := rand.Read(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create CBC IV
|
||||||
|
iv := make([]byte, des.BlockSize)
|
||||||
|
_, err := rand.Read(iv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt padded content
|
||||||
|
block, err := des.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
plaintext, err := pad(content, mode.BlockSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
cyphertext := make([]byte, len(plaintext))
|
||||||
|
mode.CryptBlocks(cyphertext, plaintext)
|
||||||
|
|
||||||
|
// Prepare ASN.1 Encrypted Content Info
|
||||||
|
eci := encryptedContentInfo{
|
||||||
|
ContentType: OIDData,
|
||||||
|
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: OIDEncryptionAlgorithmDESCBC,
|
||||||
|
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||||
|
},
|
||||||
|
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, &eci, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||||
|
var keyLen int
|
||||||
|
var algID asn1.ObjectIdentifier
|
||||||
|
switch ContentEncryptionAlgorithm {
|
||||||
|
case EncryptionAlgorithmAES128CBC:
|
||||||
|
keyLen = 16
|
||||||
|
algID = OIDEncryptionAlgorithmAES128CBC
|
||||||
|
case EncryptionAlgorithmAES256CBC:
|
||||||
|
keyLen = 32
|
||||||
|
algID = OIDEncryptionAlgorithmAES256CBC
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", ContentEncryptionAlgorithm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
// Create AES key
|
||||||
|
key = make([]byte, keyLen)
|
||||||
|
|
||||||
|
_, err := rand.Read(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create CBC IV
|
||||||
|
iv := make([]byte, aes.BlockSize)
|
||||||
|
_, err := rand.Read(iv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt padded content
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
plaintext, err := pad(content, mode.BlockSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
cyphertext := make([]byte, len(plaintext))
|
||||||
|
mode.CryptBlocks(cyphertext, plaintext)
|
||||||
|
|
||||||
|
// Prepare ASN.1 Encrypted Content Info
|
||||||
|
eci := encryptedContentInfo{
|
||||||
|
ContentType: OIDData,
|
||||||
|
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: algID,
|
||||||
|
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||||
|
},
|
||||||
|
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, &eci, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
|
// recipient keys for each recipient public key.
|
||||||
|
//
|
||||||
|
// The algorithm used to perform encryption is determined by the current value
|
||||||
|
// of the global ContentEncryptionAlgorithm package variable. By default, the
|
||||||
|
// value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the
|
||||||
|
// value before calling Encrypt(). For example:
|
||||||
|
//
|
||||||
|
// ContentEncryptionAlgorithm = EncryptionAlgorithmAES128GCM
|
||||||
|
//
|
||||||
|
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||||
|
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
|
||||||
|
var eci *encryptedContentInfo
|
||||||
|
var key []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Apply chosen symmetric encryption method
|
||||||
|
switch ContentEncryptionAlgorithm {
|
||||||
|
case EncryptionAlgorithmDESCBC:
|
||||||
|
key, eci, err = encryptDESCBC(content, nil)
|
||||||
|
case EncryptionAlgorithmAES128CBC:
|
||||||
|
fallthrough
|
||||||
|
case EncryptionAlgorithmAES256CBC:
|
||||||
|
key, eci, err = encryptAESCBC(content, nil)
|
||||||
|
case EncryptionAlgorithmAES128GCM:
|
||||||
|
fallthrough
|
||||||
|
case EncryptionAlgorithmAES256GCM:
|
||||||
|
key, eci, err = encryptAESGCM(content, nil)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare each recipient's encrypted cipher key
|
||||||
|
recipientInfos := make([]recipientInfo, len(recipients))
|
||||||
|
for i, recipient := range recipients {
|
||||||
|
encrypted, err := encryptKey(key, recipient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ias, err := cert2issuerAndSerial(recipient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
info := recipientInfo{
|
||||||
|
Version: 0,
|
||||||
|
IssuerAndSerialNumber: ias,
|
||||||
|
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: OIDEncryptionAlgorithmRSA,
|
||||||
|
},
|
||||||
|
EncryptedKey: encrypted,
|
||||||
|
}
|
||||||
|
recipientInfos[i] = info
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare envelope content
|
||||||
|
envelope := envelopedData{
|
||||||
|
EncryptedContentInfo: *eci,
|
||||||
|
Version: 0,
|
||||||
|
RecipientInfos: recipientInfos,
|
||||||
|
}
|
||||||
|
innerContent, err := asn1.Marshal(envelope)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare outer payload structure
|
||||||
|
wrapper := contentInfo{
|
||||||
|
ContentType: OIDEnvelopedData,
|
||||||
|
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||||
|
}
|
||||||
|
|
||||||
|
return asn1.Marshal(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||||
|
// encrypted using caller provided pre-shared secret.
|
||||||
|
func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
|
||||||
|
var eci *encryptedContentInfo
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
return nil, ErrPSKNotProvided
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply chosen symmetric encryption method
|
||||||
|
switch ContentEncryptionAlgorithm {
|
||||||
|
case EncryptionAlgorithmDESCBC:
|
||||||
|
_, eci, err = encryptDESCBC(content, key)
|
||||||
|
|
||||||
|
case EncryptionAlgorithmAES128GCM:
|
||||||
|
fallthrough
|
||||||
|
case EncryptionAlgorithmAES256GCM:
|
||||||
|
_, eci, err = encryptAESGCM(content, key)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare encrypted-data content
|
||||||
|
ed := encryptedData{
|
||||||
|
Version: 0,
|
||||||
|
EncryptedContentInfo: *eci,
|
||||||
|
}
|
||||||
|
innerContent, err := asn1.Marshal(ed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare outer payload structure
|
||||||
|
wrapper := contentInfo{
|
||||||
|
ContentType: OIDEncryptedData,
|
||||||
|
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||||
|
}
|
||||||
|
|
||||||
|
return asn1.Marshal(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
||||||
|
asn1Content, _ := asn1.Marshal(content)
|
||||||
|
return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
||||||
|
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
||||||
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
func pad(data []byte, blocklen int) ([]byte, error) {
|
||||||
|
if blocklen < 1 {
|
||||||
|
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||||
|
}
|
||||||
|
padlen := blocklen - (len(data) % blocklen)
|
||||||
|
if padlen == 0 {
|
||||||
|
padlen = blocklen
|
||||||
|
}
|
||||||
|
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
||||||
|
return append(data, pad...), nil
|
||||||
|
}
|
3
vendor/go.mozilla.org/pkcs7/go.mod
generated
vendored
Normal file
3
vendor/go.mozilla.org/pkcs7/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module go.mozilla.org/pkcs7
|
||||||
|
|
||||||
|
go 1.11
|
291
vendor/go.mozilla.org/pkcs7/pkcs7.go
generated
vendored
Normal file
291
vendor/go.mozilla.org/pkcs7/pkcs7.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
// Package pkcs7 implements parsing and generation of some PKCS#7 structures.
|
||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/dsa"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
_ "crypto/sha1" // for crypto.SHA1
|
||||||
|
)
|
||||||
|
|
||||||
|
// PKCS7 Represents a PKCS7 structure
|
||||||
|
type PKCS7 struct {
|
||||||
|
Content []byte
|
||||||
|
Certificates []*x509.Certificate
|
||||||
|
CRLs []pkix.CertificateList
|
||||||
|
Signers []signerInfo
|
||||||
|
raw interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type contentInfo struct {
|
||||||
|
ContentType asn1.ObjectIdentifier
|
||||||
|
Content asn1.RawValue `asn1:"explicit,optional,tag:0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnsupportedContentType is returned when a PKCS7 content is not supported.
|
||||||
|
// Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2),
|
||||||
|
// and Enveloped Data are supported (1.2.840.113549.1.7.3)
|
||||||
|
var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type")
|
||||||
|
|
||||||
|
type unsignedData []byte
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Signed Data OIDs
|
||||||
|
OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
|
||||||
|
OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
|
||||||
|
OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
|
||||||
|
OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
|
||||||
|
OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
|
||||||
|
OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
|
||||||
|
OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
|
||||||
|
|
||||||
|
// Digest Algorithms
|
||||||
|
OIDDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
|
||||||
|
OIDDigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||||
|
OIDDigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||||
|
OIDDigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||||
|
|
||||||
|
OIDDigestAlgorithmDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||||
|
OIDDigestAlgorithmDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||||
|
|
||||||
|
OIDDigestAlgorithmECDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||||
|
OIDDigestAlgorithmECDSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||||
|
OIDDigestAlgorithmECDSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||||
|
OIDDigestAlgorithmECDSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||||
|
|
||||||
|
// Signature Algorithms
|
||||||
|
OIDEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||||
|
OIDEncryptionAlgorithmRSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||||
|
OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||||
|
OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
||||||
|
OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
||||||
|
|
||||||
|
OIDEncryptionAlgorithmECDSAP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||||
|
OIDEncryptionAlgorithmECDSAP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||||
|
OIDEncryptionAlgorithmECDSAP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||||
|
|
||||||
|
// Encryption Algorithms
|
||||||
|
OIDEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
|
||||||
|
OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
|
||||||
|
OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||||
|
OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
|
||||||
|
OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||||
|
OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
|
||||||
|
switch {
|
||||||
|
case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1),
|
||||||
|
oid.Equal(OIDDigestAlgorithmDSA), oid.Equal(OIDDigestAlgorithmDSASHA1),
|
||||||
|
oid.Equal(OIDEncryptionAlgorithmRSA):
|
||||||
|
return crypto.SHA1, nil
|
||||||
|
case oid.Equal(OIDDigestAlgorithmSHA256), oid.Equal(OIDDigestAlgorithmECDSASHA256):
|
||||||
|
return crypto.SHA256, nil
|
||||||
|
case oid.Equal(OIDDigestAlgorithmSHA384), oid.Equal(OIDDigestAlgorithmECDSASHA384):
|
||||||
|
return crypto.SHA384, nil
|
||||||
|
case oid.Equal(OIDDigestAlgorithmSHA512), oid.Equal(OIDDigestAlgorithmECDSASHA512):
|
||||||
|
return crypto.SHA512, nil
|
||||||
|
}
|
||||||
|
return crypto.Hash(0), ErrUnsupportedAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDigestOIDForSignatureAlgorithm takes an x509.SignatureAlgorithm
|
||||||
|
// and returns the corresponding OID digest algorithm
|
||||||
|
func getDigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.ObjectIdentifier, error) {
|
||||||
|
switch digestAlg {
|
||||||
|
case x509.SHA1WithRSA, x509.ECDSAWithSHA1:
|
||||||
|
return OIDDigestAlgorithmSHA1, nil
|
||||||
|
case x509.SHA256WithRSA, x509.ECDSAWithSHA256:
|
||||||
|
return OIDDigestAlgorithmSHA256, nil
|
||||||
|
case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
|
||||||
|
return OIDDigestAlgorithmSHA384, nil
|
||||||
|
case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
|
||||||
|
return OIDDigestAlgorithmSHA512, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getOIDForEncryptionAlgorithm takes the private key type of the signer and
|
||||||
|
// the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm
|
||||||
|
func getOIDForEncryptionAlgorithm(pkey crypto.PrivateKey, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) {
|
||||||
|
switch pkey.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
switch {
|
||||||
|
default:
|
||||||
|
return OIDEncryptionAlgorithmRSA, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDEncryptionAlgorithmRSA):
|
||||||
|
return OIDEncryptionAlgorithmRSA, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1):
|
||||||
|
return OIDEncryptionAlgorithmRSASHA1, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256):
|
||||||
|
return OIDEncryptionAlgorithmRSASHA256, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384):
|
||||||
|
return OIDEncryptionAlgorithmRSASHA384, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512):
|
||||||
|
return OIDEncryptionAlgorithmRSASHA512, nil
|
||||||
|
}
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
switch {
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1):
|
||||||
|
return OIDDigestAlgorithmECDSASHA1, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256):
|
||||||
|
return OIDDigestAlgorithmECDSASHA256, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384):
|
||||||
|
return OIDDigestAlgorithmECDSASHA384, nil
|
||||||
|
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512):
|
||||||
|
return OIDDigestAlgorithmECDSASHA512, nil
|
||||||
|
}
|
||||||
|
case *dsa.PrivateKey:
|
||||||
|
return OIDDigestAlgorithmDSA, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("pkcs7: cannot convert encryption algorithm to oid, unknown private key type %T", pkey)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse decodes a DER encoded PKCS7 package
|
||||||
|
func Parse(data []byte) (p7 *PKCS7, err error) {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, errors.New("pkcs7: input data is empty")
|
||||||
|
}
|
||||||
|
var info contentInfo
|
||||||
|
der, err := ber2der(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rest, err := asn1.Unmarshal(der, &info)
|
||||||
|
if len(rest) > 0 {
|
||||||
|
err = asn1.SyntaxError{Msg: "trailing data"}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("--> Content Type: %s", info.ContentType)
|
||||||
|
switch {
|
||||||
|
case info.ContentType.Equal(OIDSignedData):
|
||||||
|
return parseSignedData(info.Content.Bytes)
|
||||||
|
case info.ContentType.Equal(OIDEnvelopedData):
|
||||||
|
return parseEnvelopedData(info.Content.Bytes)
|
||||||
|
case info.ContentType.Equal(OIDEncryptedData):
|
||||||
|
return parseEncryptedData(info.Content.Bytes)
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEnvelopedData(data []byte) (*PKCS7, error) {
|
||||||
|
var ed envelopedData
|
||||||
|
if _, err := asn1.Unmarshal(data, &ed); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &PKCS7{
|
||||||
|
raw: ed,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEncryptedData(data []byte) (*PKCS7, error) {
|
||||||
|
var ed encryptedData
|
||||||
|
if _, err := asn1.Unmarshal(data, &ed); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &PKCS7{
|
||||||
|
raw: ed,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (raw rawCertificates) Parse() ([]*x509.Certificate, error) {
|
||||||
|
if len(raw.Raw) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var val asn1.RawValue
|
||||||
|
if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return x509.ParseCertificates(val.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool {
|
||||||
|
return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attribute represents a key value pair attribute. Value must be marshalable byte
|
||||||
|
// `encoding/asn1`
|
||||||
|
type Attribute struct {
|
||||||
|
Type asn1.ObjectIdentifier
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type attributes struct {
|
||||||
|
types []asn1.ObjectIdentifier
|
||||||
|
values []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds the attribute, maintaining insertion order
|
||||||
|
func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) {
|
||||||
|
attrs.types = append(attrs.types, attrType)
|
||||||
|
attrs.values = append(attrs.values, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortableAttribute struct {
|
||||||
|
SortKey []byte
|
||||||
|
Attribute attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
type attributeSet []sortableAttribute
|
||||||
|
|
||||||
|
func (sa attributeSet) Len() int {
|
||||||
|
return len(sa)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa attributeSet) Less(i, j int) bool {
|
||||||
|
return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa attributeSet) Swap(i, j int) {
|
||||||
|
sa[i], sa[j] = sa[j], sa[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa attributeSet) Attributes() []attribute {
|
||||||
|
attrs := make([]attribute, len(sa))
|
||||||
|
for i, attr := range sa {
|
||||||
|
attrs[i] = attr.Attribute
|
||||||
|
}
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (attrs *attributes) ForMarshalling() ([]attribute, error) {
|
||||||
|
sortables := make(attributeSet, len(attrs.types))
|
||||||
|
for i := range sortables {
|
||||||
|
attrType := attrs.types[i]
|
||||||
|
attrValue := attrs.values[i]
|
||||||
|
asn1Value, err := asn1.Marshal(attrValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
attr := attribute{
|
||||||
|
Type: attrType,
|
||||||
|
Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag
|
||||||
|
}
|
||||||
|
encoded, err := asn1.Marshal(attr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sortables[i] = sortableAttribute{
|
||||||
|
SortKey: encoded,
|
||||||
|
Attribute: attr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(sortables)
|
||||||
|
return sortables.Attributes(), nil
|
||||||
|
}
|
429
vendor/go.mozilla.org/pkcs7/sign.go
generated
vendored
Normal file
429
vendor/go.mozilla.org/pkcs7/sign.go
generated
vendored
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/dsa"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignedData is an opaque data structure for creating signed data payloads
|
||||||
|
type SignedData struct {
|
||||||
|
sd signedData
|
||||||
|
certs []*x509.Certificate
|
||||||
|
data, messageDigest []byte
|
||||||
|
digestOid asn1.ObjectIdentifier
|
||||||
|
encryptionOid asn1.ObjectIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is
|
||||||
|
// ready to be signed via AddSigner. The digest algorithm is set to SHA1 by default
|
||||||
|
// and can be changed by calling SetDigestAlgorithm.
|
||||||
|
func NewSignedData(data []byte) (*SignedData, error) {
|
||||||
|
content, err := asn1.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ci := contentInfo{
|
||||||
|
ContentType: OIDData,
|
||||||
|
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
||||||
|
}
|
||||||
|
sd := signedData{
|
||||||
|
ContentInfo: ci,
|
||||||
|
Version: 1,
|
||||||
|
}
|
||||||
|
return &SignedData{sd: sd, data: data, digestOid: OIDDigestAlgorithmSHA1}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignerInfoConfig are optional values to include when adding a signer
|
||||||
|
type SignerInfoConfig struct {
|
||||||
|
ExtraSignedAttributes []Attribute
|
||||||
|
ExtraUnsignedAttributes []Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
type signedData struct {
|
||||||
|
Version int `asn1:"default:1"`
|
||||||
|
DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"`
|
||||||
|
ContentInfo contentInfo
|
||||||
|
Certificates rawCertificates `asn1:"optional,tag:0"`
|
||||||
|
CRLs []pkix.CertificateList `asn1:"optional,tag:1"`
|
||||||
|
SignerInfos []signerInfo `asn1:"set"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type signerInfo struct {
|
||||||
|
Version int `asn1:"default:1"`
|
||||||
|
IssuerAndSerialNumber issuerAndSerial
|
||||||
|
DigestAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
AuthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:0"`
|
||||||
|
DigestEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
EncryptedDigest []byte
|
||||||
|
UnauthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type attribute struct {
|
||||||
|
Type asn1.ObjectIdentifier
|
||||||
|
Value asn1.RawValue `asn1:"set"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAttributes(attrs []attribute) ([]byte, error) {
|
||||||
|
encodedAttributes, err := asn1.Marshal(struct {
|
||||||
|
A []attribute `asn1:"set"`
|
||||||
|
}{A: attrs})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the leading sequence octets
|
||||||
|
var raw asn1.RawValue
|
||||||
|
asn1.Unmarshal(encodedAttributes, &raw)
|
||||||
|
return raw.Bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rawCertificates struct {
|
||||||
|
Raw asn1.RawContent
|
||||||
|
}
|
||||||
|
|
||||||
|
type issuerAndSerial struct {
|
||||||
|
IssuerName asn1.RawValue
|
||||||
|
SerialNumber *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDigestAlgorithm sets the digest algorithm to be used in the signing process.
|
||||||
|
//
|
||||||
|
// This should be called before adding signers
|
||||||
|
func (sd *SignedData) SetDigestAlgorithm(d asn1.ObjectIdentifier) {
|
||||||
|
sd.digestOid = d
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEncryptionAlgorithm sets the encryption algorithm to be used in the signing process.
|
||||||
|
//
|
||||||
|
// This should be called before adding signers
|
||||||
|
func (sd *SignedData) SetEncryptionAlgorithm(d asn1.ObjectIdentifier) {
|
||||||
|
sd.encryptionOid = d
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSigner is a wrapper around AddSignerChain() that adds a signer without any parent.
|
||||||
|
func (sd *SignedData) AddSigner(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
|
||||||
|
var parents []*x509.Certificate
|
||||||
|
return sd.AddSignerChain(ee, pkey, parents, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSignerChain signs attributes about the content and adds certificates
|
||||||
|
// and signers infos to the Signed Data. The certificate and private key
|
||||||
|
// of the end-entity signer are used to issue the signature, and any
|
||||||
|
// parent of that end-entity that need to be added to the list of
|
||||||
|
// certifications can be specified in the parents slice.
|
||||||
|
//
|
||||||
|
// The signature algorithm used to hash the data is the one of the end-entity
|
||||||
|
// certificate.
|
||||||
|
func (sd *SignedData) AddSignerChain(ee *x509.Certificate, pkey crypto.PrivateKey, parents []*x509.Certificate, config SignerInfoConfig) error {
|
||||||
|
// Following RFC 2315, 9.2 SignerInfo type, the distinguished name of
|
||||||
|
// the issuer of the end-entity signer is stored in the issuerAndSerialNumber
|
||||||
|
// section of the SignedData.SignerInfo, alongside the serial number of
|
||||||
|
// the end-entity.
|
||||||
|
var ias issuerAndSerial
|
||||||
|
ias.SerialNumber = ee.SerialNumber
|
||||||
|
if len(parents) == 0 {
|
||||||
|
// no parent, the issuer is the end-entity cert itself
|
||||||
|
ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer}
|
||||||
|
} else {
|
||||||
|
err := verifyPartialChain(ee, parents)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// the first parent is the issuer
|
||||||
|
ias.IssuerName = asn1.RawValue{FullBytes: parents[0].RawSubject}
|
||||||
|
}
|
||||||
|
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers,
|
||||||
|
pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||||
|
)
|
||||||
|
hash, err := getHashForOID(sd.digestOid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := hash.New()
|
||||||
|
h.Write(sd.data)
|
||||||
|
sd.messageDigest = h.Sum(nil)
|
||||||
|
encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
attrs := &attributes{}
|
||||||
|
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
|
||||||
|
attrs.Add(OIDAttributeMessageDigest, sd.messageDigest)
|
||||||
|
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
|
||||||
|
for _, attr := range config.ExtraSignedAttributes {
|
||||||
|
attrs.Add(attr.Type, attr.Value)
|
||||||
|
}
|
||||||
|
finalAttrs, err := attrs.ForMarshalling()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
unsignedAttrs := &attributes{}
|
||||||
|
for _, attr := range config.ExtraUnsignedAttributes {
|
||||||
|
unsignedAttrs.Add(attr.Type, attr.Value)
|
||||||
|
}
|
||||||
|
finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// create signature of signed attributes
|
||||||
|
signature, err := signAttributes(finalAttrs, pkey, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signer := signerInfo{
|
||||||
|
AuthenticatedAttributes: finalAttrs,
|
||||||
|
UnauthenticatedAttributes: finalUnsignedAttrs,
|
||||||
|
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||||
|
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: encryptionOid},
|
||||||
|
IssuerAndSerialNumber: ias,
|
||||||
|
EncryptedDigest: signature,
|
||||||
|
Version: 1,
|
||||||
|
}
|
||||||
|
sd.certs = append(sd.certs, ee)
|
||||||
|
if len(parents) > 0 {
|
||||||
|
sd.certs = append(sd.certs, parents...)
|
||||||
|
}
|
||||||
|
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignWithoutAttr issues a signature on the content of the pkcs7 SignedData.
|
||||||
|
// Unlike AddSigner/AddSignerChain, it calculates the digest on the data alone
|
||||||
|
// and does not include any signed attributes like timestamp and so on.
|
||||||
|
//
|
||||||
|
// This function is needed to sign old Android APKs, something you probably
|
||||||
|
// shouldn't do unless you're maintaining backward compatibility for old
|
||||||
|
// applications.
|
||||||
|
func (sd *SignedData) SignWithoutAttr(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
|
||||||
|
var signature []byte
|
||||||
|
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers, pkix.AlgorithmIdentifier{Algorithm: sd.digestOid})
|
||||||
|
hash, err := getHashForOID(sd.digestOid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := hash.New()
|
||||||
|
h.Write(sd.data)
|
||||||
|
sd.messageDigest = h.Sum(nil)
|
||||||
|
switch pkey := pkey.(type) {
|
||||||
|
case *dsa.PrivateKey:
|
||||||
|
// dsa doesn't implement crypto.Signer so we make a special case
|
||||||
|
// https://github.com/golang/go/issues/27889
|
||||||
|
r, s, err := dsa.Sign(rand.Reader, pkey, sd.messageDigest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signature, err = asn1.Marshal(dsaSignature{r, s})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
key, ok := pkey.(crypto.Signer)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||||
|
}
|
||||||
|
signature, err = key.Sign(rand.Reader, sd.messageDigest, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ias issuerAndSerial
|
||||||
|
ias.SerialNumber = ee.SerialNumber
|
||||||
|
// no parent, the issue is the end-entity cert itself
|
||||||
|
ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer}
|
||||||
|
if sd.encryptionOid == nil {
|
||||||
|
// if the encryption algorithm wasn't set by SetEncryptionAlgorithm,
|
||||||
|
// infer it from the digest algorithm
|
||||||
|
sd.encryptionOid, err = getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signer := signerInfo{
|
||||||
|
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||||
|
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.encryptionOid},
|
||||||
|
IssuerAndSerialNumber: ias,
|
||||||
|
EncryptedDigest: signature,
|
||||||
|
Version: 1,
|
||||||
|
}
|
||||||
|
// create signature of signed attributes
|
||||||
|
sd.certs = append(sd.certs, ee)
|
||||||
|
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *signerInfo) SetUnauthenticatedAttributes(extraUnsignedAttrs []Attribute) error {
|
||||||
|
unsignedAttrs := &attributes{}
|
||||||
|
for _, attr := range extraUnsignedAttrs {
|
||||||
|
unsignedAttrs.Add(attr.Type, attr.Value)
|
||||||
|
}
|
||||||
|
finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
si.UnauthenticatedAttributes = finalUnsignedAttrs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCertificate adds the certificate to the payload. Useful for parent certificates
|
||||||
|
func (sd *SignedData) AddCertificate(cert *x509.Certificate) {
|
||||||
|
sd.certs = append(sd.certs, cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach removes content from the signed data struct to make it a detached signature.
|
||||||
|
// This must be called right before Finish()
|
||||||
|
func (sd *SignedData) Detach() {
|
||||||
|
sd.sd.ContentInfo = contentInfo{ContentType: OIDData}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignedData returns the private Signed Data
|
||||||
|
func (sd *SignedData) GetSignedData() *signedData {
|
||||||
|
return &sd.sd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish marshals the content and its signers
|
||||||
|
func (sd *SignedData) Finish() ([]byte, error) {
|
||||||
|
sd.sd.Certificates = marshalCertificates(sd.certs)
|
||||||
|
inner, err := asn1.Marshal(sd.sd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outer := contentInfo{
|
||||||
|
ContentType: OIDSignedData,
|
||||||
|
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: inner, IsCompound: true},
|
||||||
|
}
|
||||||
|
return asn1.Marshal(outer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAuthenticatedAttributes removes authenticated attributes from signedData
|
||||||
|
// similar to OpenSSL's PKCS7_NOATTR or -noattr flags
|
||||||
|
func (sd *SignedData) RemoveAuthenticatedAttributes() {
|
||||||
|
for i := range sd.sd.SignerInfos {
|
||||||
|
sd.sd.SignerInfos[i].AuthenticatedAttributes = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveUnauthenticatedAttributes removes unauthenticated attributes from signedData
|
||||||
|
func (sd *SignedData) RemoveUnauthenticatedAttributes() {
|
||||||
|
for i := range sd.sd.SignerInfos {
|
||||||
|
sd.sd.SignerInfos[i].UnauthenticatedAttributes = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyPartialChain checks that a given cert is issued by the first parent in the list,
|
||||||
|
// then continue down the path. It doesn't require the last parent to be a root CA,
|
||||||
|
// or to be trusted in any truststore. It simply verifies that the chain provided, albeit
|
||||||
|
// partial, makes sense.
|
||||||
|
func verifyPartialChain(cert *x509.Certificate, parents []*x509.Certificate) error {
|
||||||
|
if len(parents) == 0 {
|
||||||
|
return fmt.Errorf("pkcs7: zero parents provided to verify the signature of certificate %q", cert.Subject.CommonName)
|
||||||
|
}
|
||||||
|
err := cert.CheckSignatureFrom(parents[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("pkcs7: certificate signature from parent is invalid: %v", err)
|
||||||
|
}
|
||||||
|
if len(parents) == 1 {
|
||||||
|
// there is no more parent to check, return
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return verifyPartialChain(parents[0], parents[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func cert2issuerAndSerial(cert *x509.Certificate) (issuerAndSerial, error) {
|
||||||
|
var ias issuerAndSerial
|
||||||
|
// The issuer RDNSequence has to match exactly the sequence in the certificate
|
||||||
|
// We cannot use cert.Issuer.ToRDNSequence() here since it mangles the sequence
|
||||||
|
ias.IssuerName = asn1.RawValue{FullBytes: cert.RawIssuer}
|
||||||
|
ias.SerialNumber = cert.SerialNumber
|
||||||
|
|
||||||
|
return ias, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signs the DER encoded form of the attributes with the private key
|
||||||
|
func signAttributes(attrs []attribute, pkey crypto.PrivateKey, digestAlg crypto.Hash) ([]byte, error) {
|
||||||
|
attrBytes, err := marshalAttributes(attrs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h := digestAlg.New()
|
||||||
|
h.Write(attrBytes)
|
||||||
|
hash := h.Sum(nil)
|
||||||
|
|
||||||
|
// dsa doesn't implement crypto.Signer so we make a special case
|
||||||
|
// https://github.com/golang/go/issues/27889
|
||||||
|
switch pkey := pkey.(type) {
|
||||||
|
case *dsa.PrivateKey:
|
||||||
|
r, s, err := dsa.Sign(rand.Reader, pkey, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return asn1.Marshal(dsaSignature{r, s})
|
||||||
|
}
|
||||||
|
|
||||||
|
key, ok := pkey.(crypto.Signer)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||||
|
}
|
||||||
|
return key.Sign(rand.Reader, hash, digestAlg)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dsaSignature struct {
|
||||||
|
R, S *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// concats and wraps the certificates in the RawValue structure
|
||||||
|
func marshalCertificates(certs []*x509.Certificate) rawCertificates {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, cert := range certs {
|
||||||
|
buf.Write(cert.Raw)
|
||||||
|
}
|
||||||
|
rawCerts, _ := marshalCertificateBytes(buf.Bytes())
|
||||||
|
return rawCerts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even though, the tag & length are stripped out during marshalling the
|
||||||
|
// RawContent, we have to encode it into the RawContent. If its missing,
|
||||||
|
// then `asn1.Marshal()` will strip out the certificate wrapper instead.
|
||||||
|
func marshalCertificateBytes(certs []byte) (rawCertificates, error) {
|
||||||
|
var val = asn1.RawValue{Bytes: certs, Class: 2, Tag: 0, IsCompound: true}
|
||||||
|
b, err := asn1.Marshal(val)
|
||||||
|
if err != nil {
|
||||||
|
return rawCertificates{}, err
|
||||||
|
}
|
||||||
|
return rawCertificates{Raw: b}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DegenerateCertificate creates a signed data structure containing only the
|
||||||
|
// provided certificate or certificate chain.
|
||||||
|
func DegenerateCertificate(cert []byte) ([]byte, error) {
|
||||||
|
rawCert, err := marshalCertificateBytes(cert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
emptyContent := contentInfo{ContentType: OIDData}
|
||||||
|
sd := signedData{
|
||||||
|
Version: 1,
|
||||||
|
ContentInfo: emptyContent,
|
||||||
|
Certificates: rawCert,
|
||||||
|
CRLs: []pkix.CertificateList{},
|
||||||
|
}
|
||||||
|
content, err := asn1.Marshal(sd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
signedContent := contentInfo{
|
||||||
|
ContentType: OIDSignedData,
|
||||||
|
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
||||||
|
}
|
||||||
|
return asn1.Marshal(signedContent)
|
||||||
|
}
|
264
vendor/go.mozilla.org/pkcs7/verify.go
generated
vendored
Normal file
264
vendor/go.mozilla.org/pkcs7/verify.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify is a wrapper around VerifyWithChain() that initializes an empty
|
||||||
|
// trust store, effectively disabling certificate verification when validating
|
||||||
|
// a signature.
|
||||||
|
func (p7 *PKCS7) Verify() (err error) {
|
||||||
|
return p7.VerifyWithChain(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWithChain checks the signatures of a PKCS7 object.
|
||||||
|
// If truststore is not nil, it also verifies the chain of trust of the end-entity
|
||||||
|
// signer cert to one of the root in the truststore.
|
||||||
|
func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) {
|
||||||
|
if len(p7.Signers) == 0 {
|
||||||
|
return errors.New("pkcs7: Message has no signers")
|
||||||
|
}
|
||||||
|
for _, signer := range p7.Signers {
|
||||||
|
if err := verifySignature(p7, signer, truststore); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySignature(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool) (err error) {
|
||||||
|
signedData := p7.Content
|
||||||
|
ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
||||||
|
if ee == nil {
|
||||||
|
return errors.New("pkcs7: No certificate for signer")
|
||||||
|
}
|
||||||
|
signingTime := time.Now().UTC()
|
||||||
|
if len(signer.AuthenticatedAttributes) > 0 {
|
||||||
|
// TODO(fullsailor): First check the content type match
|
||||||
|
var digest []byte
|
||||||
|
err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := hash.New()
|
||||||
|
h.Write(p7.Content)
|
||||||
|
computed := h.Sum(nil)
|
||||||
|
if subtle.ConstantTimeCompare(digest, computed) != 1 {
|
||||||
|
return &MessageDigestMismatchError{
|
||||||
|
ExpectedDigest: digest,
|
||||||
|
ActualDigest: computed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
|
||||||
|
if err == nil {
|
||||||
|
// signing time found, performing validity check
|
||||||
|
if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
|
||||||
|
return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q",
|
||||||
|
signingTime.Format(time.RFC3339),
|
||||||
|
ee.NotBefore.Format(time.RFC3339),
|
||||||
|
ee.NotBefore.Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if truststore != nil {
|
||||||
|
_, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOnlySigner returns an x509.Certificate for the first signer of the signed
|
||||||
|
// data payload. If there are more or less than one signer, nil is returned
|
||||||
|
func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
|
||||||
|
if len(p7.Signers) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
signer := p7.Signers[0]
|
||||||
|
return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalSignedAttribute decodes a single attribute from the signer info
|
||||||
|
func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
|
||||||
|
sd, ok := p7.raw.(signedData)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("pkcs7: payload is not signedData content")
|
||||||
|
}
|
||||||
|
if len(sd.SignerInfos) < 1 {
|
||||||
|
return errors.New("pkcs7: payload has no signers")
|
||||||
|
}
|
||||||
|
attributes := sd.SignerInfos[0].AuthenticatedAttributes
|
||||||
|
return unmarshalAttribute(attributes, attributeType, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSignedData(data []byte) (*PKCS7, error) {
|
||||||
|
var sd signedData
|
||||||
|
asn1.Unmarshal(data, &sd)
|
||||||
|
certs, err := sd.Certificates.Parse()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
|
||||||
|
|
||||||
|
var compound asn1.RawValue
|
||||||
|
var content unsignedData
|
||||||
|
|
||||||
|
// The Content.Bytes maybe empty on PKI responses.
|
||||||
|
if len(sd.ContentInfo.Content.Bytes) > 0 {
|
||||||
|
if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Compound octet string
|
||||||
|
if compound.IsCompound {
|
||||||
|
if compound.Tag == 4 {
|
||||||
|
if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content = compound.Bytes
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// assuming this is tag 04
|
||||||
|
content = compound.Bytes
|
||||||
|
}
|
||||||
|
return &PKCS7{
|
||||||
|
Content: content,
|
||||||
|
Certificates: certs,
|
||||||
|
CRLs: sd.CRLs,
|
||||||
|
Signers: sd.SignerInfos,
|
||||||
|
raw: sd}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyCertChain takes an end-entity certs, a list of potential intermediates and a
|
||||||
|
// truststore, and built all potential chains between the EE and a trusted root.
|
||||||
|
//
|
||||||
|
// When verifying chains that may have expired, currentTime can be set to a past date
|
||||||
|
// to allow the verification to pass. If unset, currentTime is set to the current UTC time.
|
||||||
|
func verifyCertChain(ee *x509.Certificate, certs []*x509.Certificate, truststore *x509.CertPool, currentTime time.Time) (chains [][]*x509.Certificate, err error) {
|
||||||
|
intermediates := x509.NewCertPool()
|
||||||
|
for _, intermediate := range certs {
|
||||||
|
intermediates.AddCert(intermediate)
|
||||||
|
}
|
||||||
|
verifyOptions := x509.VerifyOptions{
|
||||||
|
Roots: truststore,
|
||||||
|
Intermediates: intermediates,
|
||||||
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||||
|
CurrentTime: currentTime,
|
||||||
|
}
|
||||||
|
chains, err = ee.Verify(verifyOptions)
|
||||||
|
if err != nil {
|
||||||
|
return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageDigestMismatchError is returned when the signer data digest does not
|
||||||
|
// match the computed digest for the contained content
|
||||||
|
type MessageDigestMismatchError struct {
|
||||||
|
ExpectedDigest []byte
|
||||||
|
ActualDigest []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *MessageDigestMismatchError) Error() string {
|
||||||
|
return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) {
|
||||||
|
switch {
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1):
|
||||||
|
return x509.ECDSAWithSHA1, nil
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256):
|
||||||
|
return x509.ECDSAWithSHA256, nil
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384):
|
||||||
|
return x509.ECDSAWithSHA384, nil
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512):
|
||||||
|
return x509.ECDSAWithSHA512, nil
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
|
||||||
|
switch {
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||||
|
return x509.SHA1WithRSA, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||||
|
return x509.SHA256WithRSA, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
|
||||||
|
return x509.SHA384WithRSA, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
|
||||||
|
return x509.SHA512WithRSA, nil
|
||||||
|
default:
|
||||||
|
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||||
|
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||||
|
}
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1):
|
||||||
|
switch {
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||||
|
return x509.DSAWithSHA1, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||||
|
return x509.DSAWithSHA256, nil
|
||||||
|
default:
|
||||||
|
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||||
|
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||||
|
}
|
||||||
|
case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384),
|
||||||
|
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521):
|
||||||
|
switch {
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||||
|
return x509.ECDSAWithSHA1, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||||
|
return x509.ECDSAWithSHA256, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
|
||||||
|
return x509.ECDSAWithSHA384, nil
|
||||||
|
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
|
||||||
|
return x509.ECDSAWithSHA512, nil
|
||||||
|
default:
|
||||||
|
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||||
|
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1, fmt.Errorf("pkcs7: unsupported algorithm %q",
|
||||||
|
digestEncryption.Algorithm.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
|
||||||
|
for _, cert := range certs {
|
||||||
|
if isCertMatchForIssuerAndSerial(cert, ias) {
|
||||||
|
return cert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
|
||||||
|
for _, attr := range attrs {
|
||||||
|
if attr.Type.Equal(attributeType) {
|
||||||
|
_, err := asn1.Unmarshal(attr.Value.Bytes, out)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("pkcs7: attribute type not in attributes")
|
||||||
|
}
|
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
@@ -35,8 +35,6 @@ github.com/beorn7/perks/quantile
|
|||||||
github.com/containerd/cgroups/stats/v1
|
github.com/containerd/cgroups/stats/v1
|
||||||
# github.com/containerd/containerd v1.3.2
|
# github.com/containerd/containerd v1.3.2
|
||||||
github.com/containerd/containerd/errdefs
|
github.com/containerd/containerd/errdefs
|
||||||
github.com/containerd/containerd/log
|
|
||||||
github.com/containerd/containerd/platforms
|
|
||||||
# github.com/containers/common v0.15.2
|
# github.com/containers/common v0.15.2
|
||||||
github.com/containers/common/pkg/auth
|
github.com/containers/common/pkg/auth
|
||||||
# github.com/containers/image/v5 v5.5.1
|
# github.com/containers/image/v5 v5.5.1
|
||||||
@@ -82,7 +80,7 @@ github.com/containers/image/v5/types
|
|||||||
github.com/containers/image/v5/version
|
github.com/containers/image/v5/version
|
||||||
# github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b
|
# github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b
|
||||||
github.com/containers/libtrust
|
github.com/containers/libtrust
|
||||||
# github.com/containers/ocicrypt v1.0.2
|
# github.com/containers/ocicrypt v1.0.3
|
||||||
github.com/containers/ocicrypt
|
github.com/containers/ocicrypt
|
||||||
github.com/containers/ocicrypt/blockcipher
|
github.com/containers/ocicrypt/blockcipher
|
||||||
github.com/containers/ocicrypt/config
|
github.com/containers/ocicrypt/config
|
||||||
@@ -179,8 +177,6 @@ github.com/docker/go-connections/tlsconfig
|
|||||||
github.com/docker/go-metrics
|
github.com/docker/go-metrics
|
||||||
# github.com/docker/go-units v0.4.0
|
# github.com/docker/go-units v0.4.0
|
||||||
github.com/docker/go-units
|
github.com/docker/go-units
|
||||||
# github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
|
|
||||||
github.com/fullsailor/pkcs7
|
|
||||||
# github.com/ghodss/yaml v1.0.0
|
# github.com/ghodss/yaml v1.0.0
|
||||||
github.com/ghodss/yaml
|
github.com/ghodss/yaml
|
||||||
# github.com/go-check/check v0.0.0-20180628173108-788fd7840127
|
# github.com/go-check/check v0.0.0-20180628173108-788fd7840127
|
||||||
@@ -311,6 +307,8 @@ github.com/xeipuuv/gojsonreference
|
|||||||
github.com/xeipuuv/gojsonschema
|
github.com/xeipuuv/gojsonschema
|
||||||
# go.etcd.io/bbolt v1.3.4
|
# go.etcd.io/bbolt v1.3.4
|
||||||
go.etcd.io/bbolt
|
go.etcd.io/bbolt
|
||||||
|
# go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1
|
||||||
|
go.mozilla.org/pkcs7
|
||||||
# go.opencensus.io v0.22.0
|
# go.opencensus.io v0.22.0
|
||||||
go.opencensus.io
|
go.opencensus.io
|
||||||
go.opencensus.io/internal
|
go.opencensus.io/internal
|
||||||
|
Reference in New Issue
Block a user