mirror of
https://github.com/containers/skopeo.git
synced 2025-08-30 12:30:58 +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:
parent
840c48752e
commit
2e343342d5
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ go 1.12
|
||||
require (
|
||||
github.com/containers/common v0.15.2
|
||||
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/docker/docker v1.4.2-0.20191219165747-a9416c67da9f
|
||||
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/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
|
||||
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/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
|
||||
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.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||
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/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
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
|
||||
|
||||
require (
|
||||
github.com/containerd/containerd v1.2.10
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/sirupsen/logrus v1.4.2 // 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
|
||||
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
|
||||
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/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/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/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
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.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/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-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
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/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-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
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/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
|
||||
|
||||
if gc.gpgHomeDir != "" {
|
||||
args = append([]string{"--homedir", gc.gpgHomeDir})
|
||||
args = []string{"--homedir", gc.gpgHomeDir}
|
||||
}
|
||||
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
|
||||
|
||||
if gc.gpgHomeDir != "" {
|
||||
args = append([]string{"--homedir", gc.gpgHomeDir})
|
||||
args = []string{"--homedir", gc.gpgHomeDir}
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containers/ocicrypt"
|
||||
encconfig "github.com/containers/ocicrypt/config"
|
||||
encutils "github.com/containers/ocicrypt/utils"
|
||||
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -66,6 +63,23 @@ func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, er
|
||||
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:
|
||||
// - file=<passwordfile>
|
||||
// - pass=<password>
|
||||
@ -141,33 +155,14 @@ func processPrivateKeyFiles(keyFilesAndPwds []string) ([][]byte, [][]byte, [][]b
|
||||
gpgSecretKeyRingFiles = append(gpgSecretKeyRingFiles, tmp)
|
||||
gpgSecretKeyPasswords = append(gpgSecretKeyPasswords, password)
|
||||
} 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
|
||||
}
|
||||
|
||||
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
|
||||
// information to perform decryption from command line options and possibly
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return encconfig.CryptoConfig{}, err
|
||||
@ -236,20 +238,6 @@ func CreateDecryptCryptoConfig(keys []string, decRecipients []string) (encconfig
|
||||
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
|
||||
func CreateCryptoConfig(recipients []string, keys []string) (encconfig.CryptoConfig, error) {
|
||||
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/keywrap"
|
||||
"github.com/containers/ocicrypt/utils"
|
||||
"github.com/fullsailor/pkcs7"
|
||||
"github.com/pkg/errors"
|
||||
"go.mozilla.org/pkcs7"
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// var encodeIndent = 0
|
||||
var encodeIndent = 0
|
||||
|
||||
type asn1Object interface {
|
||||
EncodeTo(writer *bytes.Buffer) error
|
||||
@ -18,7 +18,7 @@ type asn1Structured struct {
|
||||
|
||||
func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
||||
//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
|
||||
//encodeIndent++
|
||||
encodeIndent++
|
||||
inner := new(bytes.Buffer)
|
||||
for _, obj := range s.content {
|
||||
err := obj.EncodeTo(inner)
|
||||
@ -26,7 +26,7 @@ func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
//encodeIndent--
|
||||
encodeIndent--
|
||||
out.Write(s.tagBytes)
|
||||
encodeLength(out, inner.Len())
|
||||
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) {
|
||||
//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
|
||||
b := ber[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
|
||||
if tag == 0x1F {
|
||||
tag = 0
|
||||
for ber[offset] >= 0x80 {
|
||||
tag = tag*128 + ber[offset] - 0x80
|
||||
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++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
}
|
||||
tagEnd := offset
|
||||
|
||||
kind := b & 0x20
|
||||
/*
|
||||
if kind == 0 {
|
||||
fmt.Print("--> Primitive\n")
|
||||
} else {
|
||||
fmt.Print("--> Constructed\n")
|
||||
}
|
||||
*/
|
||||
if kind == 0 {
|
||||
debugprint("--> Primitive\n")
|
||||
} else {
|
||||
debugprint("--> Constructed\n")
|
||||
}
|
||||
// read length
|
||||
var length int
|
||||
l := ber[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 {
|
||||
numberOfBytes := (int)(l & 0x7F)
|
||||
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 {
|
||||
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")
|
||||
}
|
||||
//fmt.Printf("--> (compute length) indicator byte: %x\n", l)
|
||||
//fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
|
||||
debugprint("--> (compute length) indicator byte: %x\n", l)
|
||||
debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
|
||||
for i := 0; i < numberOfBytes; i++ {
|
||||
length = length*256 + (int)(ber[offset])
|
||||
offset++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
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)
|
||||
contentEnd := offset + length
|
||||
if contentEnd > len(ber) {
|
||||
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
|
||||
}
|
||||
//fmt.Printf("--> content start : %d\n", offset)
|
||||
//fmt.Printf("--> content end : %d\n", contentEnd)
|
||||
//fmt.Printf("--> content : % X\n", ber[offset:contentEnd])
|
||||
debugprint("--> content start : %d\n", offset)
|
||||
debugprint("--> content end : %d\n", contentEnd)
|
||||
debugprint("--> content : % X\n", ber[offset:contentEnd])
|
||||
var obj asn1Object
|
||||
if indefinite && kind == 0 {
|
||||
return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
|
||||
}
|
||||
if kind == 0 {
|
||||
obj = asn1Primitive{
|
||||
tagBytes: ber[tagStart:tagEnd],
|
||||
@ -205,25 +228,14 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
||||
}
|
||||
} else {
|
||||
var subObjects []asn1Object
|
||||
for (offset < contentEnd) || indefinite {
|
||||
for offset < contentEnd {
|
||||
var subObj asn1Object
|
||||
var err error
|
||||
subObj, offset, err = readObject(ber, offset)
|
||||
subObj, offset, err = readObject(ber[:contentEnd], offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
subObjects = append(subObjects, subObj)
|
||||
|
||||
if indefinite {
|
||||
terminated, err := isIndefiniteTermination(ber, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if terminated {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
obj = asn1Structured{
|
||||
tagBytes: ber[tagStart:tagEnd],
|
||||
@ -231,18 +243,9 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply indefinite form length with 0x0000 terminator.
|
||||
if indefinite {
|
||||
contentEnd = offset + 2
|
||||
}
|
||||
|
||||
return obj, contentEnd, nil
|
||||
return obj, contentEnd + hack, nil
|
||||
}
|
||||
|
||||
func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
|
||||
if len(ber) - offset < 2 {
|
||||
return false, errors.New("ber2der: Invalid BER format")
|
||||
}
|
||||
|
||||
return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
|
||||
func debugprint(format string, a ...interface{}) {
|
||||
//fmt.Printf(format, a)
|
||||
}
|
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/containerd v1.3.2
|
||||
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/pkg/auth
|
||||
# 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/libtrust v0.0.0-20190913040956-14b96171aa3b
|
||||
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/blockcipher
|
||||
github.com/containers/ocicrypt/config
|
||||
@ -179,8 +177,6 @@ github.com/docker/go-connections/tlsconfig
|
||||
github.com/docker/go-metrics
|
||||
# github.com/docker/go-units v0.4.0
|
||||
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
|
||||
# github.com/go-check/check v0.0.0-20180628173108-788fd7840127
|
||||
@ -311,6 +307,8 @@ github.com/xeipuuv/gojsonreference
|
||||
github.com/xeipuuv/gojsonschema
|
||||
# go.etcd.io/bbolt v1.3.4
|
||||
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
|
||||
go.opencensus.io/internal
|
||||
|
Loading…
Reference in New Issue
Block a user