mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-08 14:23:30 +00:00
Merge pull request #60373 from sttts/sttts-1.10-cfssl
Automatic merge from submit-queue (batch tested with PRs 60373, 61098, 61352, 61359, 61362). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Bump cfssl to be compatible with Go 1.10
This commit is contained in:
131
Godeps/Godeps.json
generated
131
Godeps/Godeps.json
generated
@@ -367,68 +367,68 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/auth",
|
"ImportPath": "github.com/cloudflare/cfssl/auth",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/certdb",
|
"ImportPath": "github.com/cloudflare/cfssl/certdb",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/config",
|
"ImportPath": "github.com/cloudflare/cfssl/config",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7",
|
"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/csr",
|
"ImportPath": "github.com/cloudflare/cfssl/csr",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/errors",
|
"ImportPath": "github.com/cloudflare/cfssl/errors",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/helpers",
|
"ImportPath": "github.com/cloudflare/cfssl/helpers",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/helpers/derhelpers",
|
"ImportPath": "github.com/cloudflare/cfssl/helpers/derhelpers",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/info",
|
"ImportPath": "github.com/cloudflare/cfssl/info",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/log",
|
"ImportPath": "github.com/cloudflare/cfssl/log",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/ocsp/config",
|
"ImportPath": "github.com/cloudflare/cfssl/ocsp/config",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/signer",
|
"ImportPath": "github.com/cloudflare/cfssl/signer",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/cloudflare/cfssl/signer/local",
|
"ImportPath": "github.com/cloudflare/cfssl/signer/local",
|
||||||
"Comment": "1.2.0",
|
"Comment": "1.3.1",
|
||||||
"Rev": "db0d0650b6496bfe8061ec56a92edd32d8e75c30"
|
"Rev": "4e2dcbde500472449917533851bf4bae9bdff562"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/clusterhq/flocker-go",
|
"ImportPath": "github.com/clusterhq/flocker-go",
|
||||||
@@ -1689,24 +1689,36 @@
|
|||||||
"Rev": "2e02d28350c5fbbad9cfb7e5a1733468b75ab3f9"
|
"Rev": "2e02d28350c5fbbad9cfb7e5a1733468b75ab3f9"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/certificate-transparency/go",
|
"ImportPath": "github.com/google/certificate-transparency-go",
|
||||||
"Rev": "af98904302724c29aa6659ca372d41c9687de2b7"
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/certificate-transparency/go/asn1",
|
"ImportPath": "github.com/google/certificate-transparency-go/asn1",
|
||||||
"Rev": "af98904302724c29aa6659ca372d41c9687de2b7"
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/certificate-transparency/go/client",
|
"ImportPath": "github.com/google/certificate-transparency-go/client",
|
||||||
"Rev": "af98904302724c29aa6659ca372d41c9687de2b7"
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/certificate-transparency/go/x509",
|
"ImportPath": "github.com/google/certificate-transparency-go/client/configpb",
|
||||||
"Rev": "af98904302724c29aa6659ca372d41c9687de2b7"
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/certificate-transparency/go/x509/pkix",
|
"ImportPath": "github.com/google/certificate-transparency-go/jsonclient",
|
||||||
"Rev": "af98904302724c29aa6659ca372d41c9687de2b7"
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/google/certificate-transparency-go/tls",
|
||||||
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/google/certificate-transparency-go/x509",
|
||||||
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/google/certificate-transparency-go/x509/pkix",
|
||||||
|
"Rev": "1bec4527572c443752ad4f2830bef88be0533236"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/gofuzz",
|
"ImportPath": "github.com/google/gofuzz",
|
||||||
@@ -1964,7 +1976,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/inconshreveable/mousetrap",
|
"ImportPath": "github.com/inconshreveable/mousetrap",
|
||||||
"Comment": "v1.0",
|
|
||||||
"Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
"Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2122,10 +2133,6 @@
|
|||||||
"ImportPath": "github.com/mohae/deepcopy",
|
"ImportPath": "github.com/mohae/deepcopy",
|
||||||
"Rev": "491d3605edfb866af34a48075bd4355ac1bf46ca"
|
"Rev": "491d3605edfb866af34a48075bd4355ac1bf46ca"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mreiferson/go-httpclient",
|
|
||||||
"Rev": "31f0106b4474f14bc441575c19d3a5fa21aa1f6c"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mrunalp/fileutils",
|
"ImportPath": "github.com/mrunalp/fileutils",
|
||||||
"Rev": "4ee1cc9a80582a0c75febdd5cfa779ee4361cbca"
|
"Rev": "4ee1cc9a80582a0c75febdd5cfa779ee4361cbca"
|
||||||
@@ -2449,7 +2456,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pelletier/go-buffruneio",
|
"ImportPath": "github.com/pelletier/go-buffruneio",
|
||||||
"Comment": "v0.1.0",
|
|
||||||
"Rev": "df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d"
|
"Rev": "df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2799,7 +2805,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/xiang90/probing",
|
"ImportPath": "github.com/xiang90/probing",
|
||||||
"Comment": "0.0.1",
|
|
||||||
"Rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2"
|
"Rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2813,51 +2818,67 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/cryptobyte",
|
||||||
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/cryptobyte/asn1",
|
||||||
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519",
|
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/internal/chacha20",
|
||||||
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/nacl/secretbox",
|
"ImportPath": "golang.org/x/crypto/nacl/secretbox",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ocsp",
|
||||||
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/pkcs12",
|
"ImportPath": "golang.org/x/crypto/pkcs12",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/pkcs12/internal/rc2",
|
"ImportPath": "golang.org/x/crypto/pkcs12/internal/rc2",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/poly1305",
|
"ImportPath": "golang.org/x/crypto/poly1305",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh",
|
"ImportPath": "golang.org/x/crypto/ssh",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/exp/inotify",
|
"ImportPath": "golang.org/x/exp/inotify",
|
||||||
|
|||||||
819
Godeps/LICENSES
generated
819
Godeps/LICENSES
generated
@@ -56118,7 +56118,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/google/certificate-transparency/go licensed under: =
|
= vendor/github.com/google/certificate-transparency-go licensed under: =
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
@@ -56323,12 +56323,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
= vendor/github.com/google/certificate-transparency/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/google/certificate-transparency/go/asn1 licensed under: =
|
= vendor/github.com/google/certificate-transparency-go/asn1 licensed under: =
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
@@ -56533,12 +56533,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
= vendor/github.com/google/certificate-transparency/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/google/certificate-transparency/go/client licensed under: =
|
= vendor/github.com/google/certificate-transparency-go/client licensed under: =
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
@@ -56743,12 +56743,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
= vendor/github.com/google/certificate-transparency/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/google/certificate-transparency/go/x509 licensed under: =
|
= vendor/github.com/google/certificate-transparency-go/client/configpb licensed under: =
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
@@ -56953,12 +56953,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
= vendor/github.com/google/certificate-transparency/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/google/certificate-transparency/go/x509/pkix licensed under: =
|
= vendor/github.com/google/certificate-transparency-go/jsonclient licensed under: =
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
@@ -57163,7 +57163,637 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
= vendor/github.com/google/certificate-transparency/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/tls licensed under: =
|
||||||
|
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/x509 licensed under: =
|
||||||
|
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/x509/pkix licensed under: =
|
||||||
|
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
= vendor/github.com/google/certificate-transparency-go/LICENSE 3b83ef96387f14655fc854ddc3c6bd57
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
@@ -72127,35 +72757,6 @@ SOFTWARE.
|
|||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
= vendor/github.com/mreiferson/go-httpclient licensed under: =
|
|
||||||
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2012 Matt Reiferson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
= vendor/github.com/mreiferson/go-httpclient/LICENSE 443af26efefd8192911d22fb48b35824
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/github.com/mrunalp/fileutils licensed under: =
|
= vendor/github.com/mrunalp/fileutils licensed under: =
|
||||||
|
|
||||||
@@ -88299,6 +88900,76 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/golang.org/x/crypto/cryptobyte licensed under: =
|
||||||
|
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
= vendor/golang.org/x/crypto/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/golang.org/x/crypto/cryptobyte/asn1 licensed under: =
|
||||||
|
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
= vendor/golang.org/x/crypto/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/golang.org/x/crypto/curve25519 licensed under: =
|
= vendor/golang.org/x/crypto/curve25519 licensed under: =
|
||||||
|
|
||||||
@@ -88404,6 +89075,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/golang.org/x/crypto/internal/chacha20 licensed under: =
|
||||||
|
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
= vendor/golang.org/x/crypto/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/golang.org/x/crypto/nacl/secretbox licensed under: =
|
= vendor/golang.org/x/crypto/nacl/secretbox licensed under: =
|
||||||
|
|
||||||
@@ -88439,6 +89145,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/golang.org/x/crypto/ocsp licensed under: =
|
||||||
|
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
= vendor/golang.org/x/crypto/LICENSE 5d4950ecb7b26d2c5e4e7b4e0dd74707
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/golang.org/x/crypto/pkcs12 licensed under: =
|
= vendor/golang.org/x/crypto/pkcs12 licensed under: =
|
||||||
|
|
||||||
|
|||||||
@@ -608,15 +608,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
16
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
16
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
@@ -584,35 +584,35 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/bcrypt",
|
"ImportPath": "golang.org/x/crypto/bcrypt",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519",
|
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/nacl/secretbox",
|
"ImportPath": "golang.org/x/crypto/nacl/secretbox",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/poly1305",
|
"ImportPath": "golang.org/x/crypto/poly1305",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
2
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
2
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
@@ -164,7 +164,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
@@ -284,7 +284,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
2
staging/src/k8s.io/metrics/Godeps/Godeps.json
generated
2
staging/src/k8s.io/metrics/Godeps/Godeps.json
generated
@@ -68,7 +68,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
@@ -264,7 +264,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
"ImportPath": "golang.org/x/crypto/ssh/terminal",
|
||||||
"Rev": "81e90905daefcd6fd217b62423c0908922eadb30"
|
"Rev": "49796115aa4b964c318aad4f3084fdb41e9aa067"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
|||||||
6
vendor/BUILD
vendored
6
vendor/BUILD
vendored
@@ -240,7 +240,7 @@ filegroup(
|
|||||||
"//vendor/github.com/google/cadvisor/validate:all-srcs",
|
"//vendor/github.com/google/cadvisor/validate:all-srcs",
|
||||||
"//vendor/github.com/google/cadvisor/version:all-srcs",
|
"//vendor/github.com/google/cadvisor/version:all-srcs",
|
||||||
"//vendor/github.com/google/cadvisor/zfs:all-srcs",
|
"//vendor/github.com/google/cadvisor/zfs:all-srcs",
|
||||||
"//vendor/github.com/google/certificate-transparency/go:all-srcs",
|
"//vendor/github.com/google/certificate-transparency-go:all-srcs",
|
||||||
"//vendor/github.com/google/gofuzz:all-srcs",
|
"//vendor/github.com/google/gofuzz:all-srcs",
|
||||||
"//vendor/github.com/google/uuid:all-srcs",
|
"//vendor/github.com/google/uuid:all-srcs",
|
||||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:all-srcs",
|
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:all-srcs",
|
||||||
@@ -293,7 +293,6 @@ filegroup(
|
|||||||
"//vendor/github.com/mitchellh/go-wordwrap:all-srcs",
|
"//vendor/github.com/mitchellh/go-wordwrap:all-srcs",
|
||||||
"//vendor/github.com/mitchellh/mapstructure:all-srcs",
|
"//vendor/github.com/mitchellh/mapstructure:all-srcs",
|
||||||
"//vendor/github.com/mohae/deepcopy:all-srcs",
|
"//vendor/github.com/mohae/deepcopy:all-srcs",
|
||||||
"//vendor/github.com/mreiferson/go-httpclient:all-srcs",
|
|
||||||
"//vendor/github.com/mrunalp/fileutils:all-srcs",
|
"//vendor/github.com/mrunalp/fileutils:all-srcs",
|
||||||
"//vendor/github.com/mvdan/xurls:all-srcs",
|
"//vendor/github.com/mvdan/xurls:all-srcs",
|
||||||
"//vendor/github.com/mxk/go-flowrate/flowrate:all-srcs",
|
"//vendor/github.com/mxk/go-flowrate/flowrate:all-srcs",
|
||||||
@@ -353,9 +352,12 @@ filegroup(
|
|||||||
"//vendor/go4.org/errorutil:all-srcs",
|
"//vendor/go4.org/errorutil:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/bcrypt:all-srcs",
|
"//vendor/golang.org/x/crypto/bcrypt:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/blowfish:all-srcs",
|
"//vendor/golang.org/x/crypto/blowfish:all-srcs",
|
||||||
|
"//vendor/golang.org/x/crypto/cryptobyte:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/curve25519:all-srcs",
|
"//vendor/golang.org/x/crypto/curve25519:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/ed25519:all-srcs",
|
"//vendor/golang.org/x/crypto/ed25519:all-srcs",
|
||||||
|
"//vendor/golang.org/x/crypto/internal/chacha20:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/nacl/secretbox:all-srcs",
|
"//vendor/golang.org/x/crypto/nacl/secretbox:all-srcs",
|
||||||
|
"//vendor/golang.org/x/crypto/ocsp:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/pkcs12:all-srcs",
|
"//vendor/golang.org/x/crypto/pkcs12:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/poly1305:all-srcs",
|
"//vendor/golang.org/x/crypto/poly1305:all-srcs",
|
||||||
"//vendor/golang.org/x/crypto/salsa20/salsa:all-srcs",
|
"//vendor/golang.org/x/crypto/salsa20/salsa:all-srcs",
|
||||||
|
|||||||
33
vendor/github.com/cloudflare/cfssl/certdb/README.md
generated
vendored
33
vendor/github.com/cloudflare/cfssl/certdb/README.md
generated
vendored
@@ -16,21 +16,26 @@ A database is required for the following:
|
|||||||
|
|
||||||
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
|
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
|
||||||
Currently supported:
|
Currently supported:
|
||||||
- SQLite in sqlite
|
- MySQL in mysql
|
||||||
- PostgreSQL in pg
|
- PostgreSQL in pg
|
||||||
|
- SQLite in sqlite
|
||||||
|
|
||||||
### Get goose
|
### Get goose
|
||||||
|
|
||||||
go get https://bitbucket.org/liamstask/goose/
|
go get bitbucket.org/liamstask/goose/cmd/goose
|
||||||
|
|
||||||
### Use goose to start and terminate a SQLite DB
|
### Use goose to start and terminate a MySQL DB
|
||||||
To start a SQLite DB using goose:
|
To start a MySQL using goose:
|
||||||
|
|
||||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up'
|
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
|
||||||
|
|
||||||
To tear down a SQLite DB using goose
|
To tear down a MySQL DB using goose
|
||||||
|
|
||||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
|
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
|
||||||
|
|
||||||
|
Note: the administration of MySQL DB is not included. We assume
|
||||||
|
the databases being connected to are already created and access control
|
||||||
|
is properly handled.
|
||||||
|
|
||||||
### Use goose to start and terminate a PostgreSQL DB
|
### Use goose to start and terminate a PostgreSQL DB
|
||||||
To start a PostgreSQL using goose:
|
To start a PostgreSQL using goose:
|
||||||
@@ -43,7 +48,16 @@ To tear down a PostgreSQL DB using goose
|
|||||||
|
|
||||||
Note: the administration of PostgreSQL DB is not included. We assume
|
Note: the administration of PostgreSQL DB is not included. We assume
|
||||||
the databases being connected to are already created and access control
|
the databases being connected to are already created and access control
|
||||||
are properly handled.
|
is properly handled.
|
||||||
|
|
||||||
|
### Use goose to start and terminate a SQLite DB
|
||||||
|
To start a SQLite DB using goose:
|
||||||
|
|
||||||
|
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
|
||||||
|
|
||||||
|
To tear down a SQLite DB using goose
|
||||||
|
|
||||||
|
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
|
||||||
|
|
||||||
## CFSSL Configuration
|
## CFSSL Configuration
|
||||||
|
|
||||||
@@ -56,3 +70,6 @@ or
|
|||||||
|
|
||||||
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
|
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
{"driver":"mysql","data_source":"user:password@tcp(hostname:3306)/db?parseTime=true"}
|
||||||
|
|||||||
2
vendor/github.com/cloudflare/cfssl/certdb/certdb.go
generated
vendored
2
vendor/github.com/cloudflare/cfssl/certdb/certdb.go
generated
vendored
@@ -31,6 +31,8 @@ type Accessor interface {
|
|||||||
InsertCertificate(cr CertificateRecord) error
|
InsertCertificate(cr CertificateRecord) error
|
||||||
GetCertificate(serial, aki string) ([]CertificateRecord, error)
|
GetCertificate(serial, aki string) ([]CertificateRecord, error)
|
||||||
GetUnexpiredCertificates() ([]CertificateRecord, error)
|
GetUnexpiredCertificates() ([]CertificateRecord, error)
|
||||||
|
GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
|
||||||
|
GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
|
||||||
RevokeCertificate(serial, aki string, reasonCode int) error
|
RevokeCertificate(serial, aki string, reasonCode int) error
|
||||||
InsertOCSP(rr OCSPRecord) error
|
InsertOCSP(rr OCSPRecord) error
|
||||||
GetOCSP(serial, aki string) ([]OCSPRecord, error)
|
GetOCSP(serial, aki string) ([]OCSPRecord, error)
|
||||||
|
|||||||
98
vendor/github.com/cloudflare/cfssl/config/config.go
generated
vendored
98
vendor/github.com/cloudflare/cfssl/config/config.go
generated
vendored
@@ -2,6 +2,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -59,6 +60,15 @@ type AuthRemote struct {
|
|||||||
AuthKeyName string `json:"auth_key"`
|
AuthKeyName string `json:"auth_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAConstraint specifies various CA constraints on the signed certificate.
|
||||||
|
// CAConstraint would verify against (and override) the CA
|
||||||
|
// extensions in the given CSR.
|
||||||
|
type CAConstraint struct {
|
||||||
|
IsCA bool `json:"is_ca"`
|
||||||
|
MaxPathLen int `json:"max_path_len"`
|
||||||
|
MaxPathLenZero bool `json:"max_path_len_zero"`
|
||||||
|
}
|
||||||
|
|
||||||
// A SigningProfile stores information that the CA needs to store
|
// A SigningProfile stores information that the CA needs to store
|
||||||
// signature policy.
|
// signature policy.
|
||||||
type SigningProfile struct {
|
type SigningProfile struct {
|
||||||
@@ -66,7 +76,7 @@ type SigningProfile struct {
|
|||||||
IssuerURL []string `json:"issuer_urls"`
|
IssuerURL []string `json:"issuer_urls"`
|
||||||
OCSP string `json:"ocsp_url"`
|
OCSP string `json:"ocsp_url"`
|
||||||
CRL string `json:"crl_url"`
|
CRL string `json:"crl_url"`
|
||||||
CA bool `json:"is_ca"`
|
CAConstraint CAConstraint `json:"ca_constraint"`
|
||||||
OCSPNoCheck bool `json:"ocsp_no_check"`
|
OCSPNoCheck bool `json:"ocsp_no_check"`
|
||||||
ExpiryString string `json:"expiry"`
|
ExpiryString string `json:"expiry"`
|
||||||
BackdateString string `json:"backdate"`
|
BackdateString string `json:"backdate"`
|
||||||
@@ -86,6 +96,8 @@ type SigningProfile struct {
|
|||||||
Provider auth.Provider
|
Provider auth.Provider
|
||||||
RemoteProvider auth.Provider
|
RemoteProvider auth.Provider
|
||||||
RemoteServer string
|
RemoteServer string
|
||||||
|
RemoteCAs *x509.CertPool
|
||||||
|
ClientCert *tls.Certificate
|
||||||
CSRWhitelist *CSRWhitelist
|
CSRWhitelist *CSRWhitelist
|
||||||
NameWhitelist *regexp.Regexp
|
NameWhitelist *regexp.Regexp
|
||||||
ExtensionWhitelist map[string]bool
|
ExtensionWhitelist map[string]bool
|
||||||
@@ -303,6 +315,44 @@ func (p *Signing) OverrideRemotes(remote string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
|
||||||
|
// authenticated TLS remote requests
|
||||||
|
func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
|
||||||
|
if certFile != "" && keyFile != "" {
|
||||||
|
cert, err := helpers.LoadClientCertificate(certFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, profile := range p.Profiles {
|
||||||
|
profile.ClientCert = cert
|
||||||
|
}
|
||||||
|
p.Default.ClientCert = cert
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
|
||||||
|
// remote requests
|
||||||
|
func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
|
||||||
|
if caFile != "" {
|
||||||
|
remoteCAs, err := helpers.LoadPEMCertPool(caFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.SetRemoteCAs(remoteCAs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRemoteCAs updates the properties to set remote CAs for TLS
|
||||||
|
// remote requests
|
||||||
|
func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
|
||||||
|
for _, profile := range p.Profiles {
|
||||||
|
profile.RemoteCAs = remoteCAs
|
||||||
|
}
|
||||||
|
p.Default.RemoteCAs = remoteCAs
|
||||||
|
}
|
||||||
|
|
||||||
// NeedsRemoteSigner returns true if one of the profiles has a remote set
|
// NeedsRemoteSigner returns true if one of the profiles has a remote set
|
||||||
func (p *Signing) NeedsRemoteSigner() bool {
|
func (p *Signing) NeedsRemoteSigner() bool {
|
||||||
for _, profile := range p.Profiles {
|
for _, profile := range p.Profiles {
|
||||||
@@ -360,6 +410,11 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
|
||||||
|
log.Debugf("invalid auth remote profile: no remote signer specified")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if p.RemoteName != "" {
|
if p.RemoteName != "" {
|
||||||
log.Debugf("validate remote profile")
|
log.Debugf("validate remote profile")
|
||||||
|
|
||||||
@@ -375,6 +430,7 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
|
|||||||
|
|
||||||
if p.AuthRemote.RemoteName != "" {
|
if p.AuthRemote.RemoteName != "" {
|
||||||
log.Debugf("invalid remote profile: auth remote is also specified")
|
log.Debugf("invalid remote profile: auth remote is also specified")
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
} else if p.AuthRemote.RemoteName != "" {
|
} else if p.AuthRemote.RemoteName != "" {
|
||||||
log.Debugf("validate auth remote profile")
|
log.Debugf("validate auth remote profile")
|
||||||
@@ -409,6 +465,43 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This checks if the SigningProfile object contains configurations that are only effective with a local signer
|
||||||
|
// which has access to CA private key.
|
||||||
|
func (p *SigningProfile) hasLocalConfig() bool {
|
||||||
|
if p.Usage != nil ||
|
||||||
|
p.IssuerURL != nil ||
|
||||||
|
p.OCSP != "" ||
|
||||||
|
p.ExpiryString != "" ||
|
||||||
|
p.BackdateString != "" ||
|
||||||
|
p.CAConstraint.IsCA != false ||
|
||||||
|
!p.NotBefore.IsZero() ||
|
||||||
|
!p.NotAfter.IsZero() ||
|
||||||
|
p.NameWhitelistString != "" ||
|
||||||
|
len(p.CTLogServers) != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// warnSkippedSettings prints a log warning message about skipped settings
|
||||||
|
// in a SigningProfile, usually due to remote signer.
|
||||||
|
func (p *Signing) warnSkippedSettings() {
|
||||||
|
const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped`
|
||||||
|
if p == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() {
|
||||||
|
log.Warning("default profile points to a remote signer: ", warningMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, profile := range p.Profiles {
|
||||||
|
if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() {
|
||||||
|
log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Signing codifies the signature configuration policy for a CA.
|
// Signing codifies the signature configuration policy for a CA.
|
||||||
type Signing struct {
|
type Signing struct {
|
||||||
Profiles map[string]*SigningProfile `json:"profiles"`
|
Profiles map[string]*SigningProfile `json:"profiles"`
|
||||||
@@ -450,6 +543,9 @@ func (p *Signing) Valid() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.warnSkippedSettings()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go
generated
vendored
2
vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
// Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
|
// Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
|
||||||
// used to package certificates and CRLs. Using openssl, every certificate converted
|
// used to package certificates and CRLs. Using openssl, every certificate converted
|
||||||
// to PKCS #7 format from another encoding such as PEM conforms to this implementation.
|
// to PKCS #7 format from another encoding such as PEM conforms to this implementation.
|
||||||
// reference: https://www.openssl.org/docs/apps/crl2pkcs7.html
|
// reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
|
||||||
//
|
//
|
||||||
// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
|
// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
|
||||||
//
|
//
|
||||||
|
|||||||
88
vendor/github.com/cloudflare/cfssl/csr/csr.go
generated
vendored
88
vendor/github.com/cloudflare/cfssl/csr/csr.go
generated
vendored
@@ -9,6 +9,7 @@ import (
|
|||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
@@ -46,8 +47,8 @@ type KeyRequest interface {
|
|||||||
|
|
||||||
// A BasicKeyRequest contains the algorithm and key size for a new private key.
|
// A BasicKeyRequest contains the algorithm and key size for a new private key.
|
||||||
type BasicKeyRequest struct {
|
type BasicKeyRequest struct {
|
||||||
A string `json:"algo"`
|
A string `json:"algo" yaml:"algo"`
|
||||||
S int `json:"size"`
|
S int `json:"size" yaml:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBasicKeyRequest returns a default BasicKeyRequest.
|
// NewBasicKeyRequest returns a default BasicKeyRequest.
|
||||||
@@ -129,19 +130,21 @@ func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
|
|||||||
|
|
||||||
// CAConfig is a section used in the requests initialising a new CA.
|
// CAConfig is a section used in the requests initialising a new CA.
|
||||||
type CAConfig struct {
|
type CAConfig struct {
|
||||||
PathLength int `json:"pathlen"`
|
PathLength int `json:"pathlen" yaml:"pathlen"`
|
||||||
Expiry string `json:"expiry"`
|
PathLenZero bool `json:"pathlenzero" yaml:"pathlenzero"`
|
||||||
|
Expiry string `json:"expiry" yaml:"expiry"`
|
||||||
|
Backdate string `json:"backdate" yaml:"backdate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A CertificateRequest encapsulates the API interface to the
|
// A CertificateRequest encapsulates the API interface to the
|
||||||
// certificate request functionality.
|
// certificate request functionality.
|
||||||
type CertificateRequest struct {
|
type CertificateRequest struct {
|
||||||
CN string
|
CN string
|
||||||
Names []Name `json:"names"`
|
Names []Name `json:"names" yaml:"names"`
|
||||||
Hosts []string `json:"hosts"`
|
Hosts []string `json:"hosts" yaml:"hosts"`
|
||||||
KeyRequest KeyRequest `json:"key,omitempty"`
|
KeyRequest KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
|
||||||
CA *CAConfig `json:"ca,omitempty"`
|
CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
|
||||||
SerialNumber string `json:"serialnumber,omitempty"`
|
SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new, empty CertificateRequest with a
|
// New returns a new, empty CertificateRequest with a
|
||||||
@@ -175,6 +178,12 @@ func (cr *CertificateRequest) Name() pkix.Name {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BasicConstraints CSR information RFC 5280, 4.2.1.9
|
||||||
|
type BasicConstraints struct {
|
||||||
|
IsCA bool `asn1:"optional"`
|
||||||
|
MaxPathLen int `asn1:"optional,default:-1"`
|
||||||
|
}
|
||||||
|
|
||||||
// ParseRequest takes a certificate request and generates a key and
|
// ParseRequest takes a certificate request and generates a key and
|
||||||
// CSR from it. It does no validation -- caveat emptor. It will,
|
// CSR from it. It does no validation -- caveat emptor. It will,
|
||||||
// however, fail if the key request is not valid (i.e., an unsupported
|
// however, fail if the key request is not valid (i.e., an unsupported
|
||||||
@@ -217,34 +226,11 @@ func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
|
|||||||
panic("Generate should have failed to produce a valid key.")
|
panic("Generate should have failed to produce a valid key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
var tpl = x509.CertificateRequest{
|
csr, err = Generate(priv.(crypto.Signer), req)
|
||||||
Subject: req.Name(),
|
|
||||||
SignatureAlgorithm: req.KeyRequest.SigAlgo(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range req.Hosts {
|
|
||||||
if ip := net.ParseIP(req.Hosts[i]); ip != nil {
|
|
||||||
tpl.IPAddresses = append(tpl.IPAddresses, ip)
|
|
||||||
} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
|
|
||||||
tpl.EmailAddresses = append(tpl.EmailAddresses, req.Hosts[i])
|
|
||||||
} else {
|
|
||||||
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to generate a CSR: %v", err)
|
log.Errorf("failed to generate a CSR: %v", err)
|
||||||
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
|
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
block := pem.Block{
|
|
||||||
Type: "CERTIFICATE REQUEST",
|
|
||||||
Bytes: csr,
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("encoded CSR")
|
|
||||||
csr = pem.EncodeToMemory(&block)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +251,7 @@ func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
|
|||||||
// issue date and expiry date.
|
// issue date and expiry date.
|
||||||
req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
|
req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
|
||||||
req.CA.PathLength = cert.MaxPathLen
|
req.CA.PathLength = cert.MaxPathLen
|
||||||
|
req.CA.PathLenZero = cert.MaxPathLenZero
|
||||||
}
|
}
|
||||||
|
|
||||||
return req
|
return req
|
||||||
@@ -341,7 +328,7 @@ func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, er
|
|||||||
err = g.Validator(req)
|
err = g.Validator(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("invalid request: %v", err)
|
log.Warningf("invalid request: %v", err)
|
||||||
return
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
csr, key, err = ParseRequest(req)
|
csr, key, err = ParseRequest(req)
|
||||||
@@ -377,7 +364,7 @@ func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
|
|||||||
// Generate creates a new CSR from a CertificateRequest structure and
|
// Generate creates a new CSR from a CertificateRequest structure and
|
||||||
// an existing key. The KeyRequest field is ignored.
|
// an existing key. The KeyRequest field is ignored.
|
||||||
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
|
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
|
||||||
sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256)
|
sigAlgo := helpers.SignerAlgo(priv)
|
||||||
if sigAlgo == x509.UnknownSignatureAlgorithm {
|
if sigAlgo == x509.UnknownSignatureAlgorithm {
|
||||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
|
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
|
||||||
}
|
}
|
||||||
@@ -397,6 +384,14 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.CA != nil {
|
||||||
|
err = appendCAInfoToCSR(req.CA, &tpl)
|
||||||
|
if err != nil {
|
||||||
|
err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to generate a CSR: %v", err)
|
log.Errorf("failed to generate a CSR: %v", err)
|
||||||
@@ -412,3 +407,26 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
|
|||||||
csr = pem.EncodeToMemory(&block)
|
csr = pem.EncodeToMemory(&block)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
|
||||||
|
func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
|
||||||
|
pathlen := reqConf.PathLength
|
||||||
|
if pathlen == 0 && !reqConf.PathLenZero {
|
||||||
|
pathlen = -1
|
||||||
|
}
|
||||||
|
val, err := asn1.Marshal(BasicConstraints{true, pathlen})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
csr.ExtraExtensions = []pkix.Extension{
|
||||||
|
{
|
||||||
|
Id: asn1.ObjectIdentifier{2, 5, 29, 19},
|
||||||
|
Value: val,
|
||||||
|
Critical: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
7
vendor/github.com/cloudflare/cfssl/errors/error.go
generated
vendored
7
vendor/github.com/cloudflare/cfssl/errors/error.go
generated
vendored
@@ -149,6 +149,8 @@ const (
|
|||||||
|
|
||||||
// UnknownProfile indicates that the profile does not exist.
|
// UnknownProfile indicates that the profile does not exist.
|
||||||
UnknownProfile // 54XX
|
UnknownProfile // 54XX
|
||||||
|
|
||||||
|
UnmatchedWhitelist // 55xx
|
||||||
)
|
)
|
||||||
|
|
||||||
// The following are API client related errors, and should be
|
// The following are API client related errors, and should be
|
||||||
@@ -189,6 +191,9 @@ const (
|
|||||||
// PrecertSubmissionFailed occurs when submitting a precertificate to
|
// PrecertSubmissionFailed occurs when submitting a precertificate to
|
||||||
// a log server fails
|
// a log server fails
|
||||||
PrecertSubmissionFailed = 100 * (iota + 1)
|
PrecertSubmissionFailed = 100 * (iota + 1)
|
||||||
|
// CTClientConstructionFailed occurs when the construction of a new
|
||||||
|
// github.com/google/certificate-transparency client fails.
|
||||||
|
CTClientConstructionFailed
|
||||||
)
|
)
|
||||||
|
|
||||||
// Certificate persistence related errors specified with CertStoreError
|
// Certificate persistence related errors specified with CertStoreError
|
||||||
@@ -313,6 +318,8 @@ func New(category Category, reason Reason) *Error {
|
|||||||
msg = "Policy violation request"
|
msg = "Policy violation request"
|
||||||
case UnknownProfile:
|
case UnknownProfile:
|
||||||
msg = "Unknown policy profile"
|
msg = "Unknown policy profile"
|
||||||
|
case UnmatchedWhitelist:
|
||||||
|
msg = "Request does not match policy whitelist"
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
|
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
|
||||||
reason))
|
reason))
|
||||||
|
|||||||
3
vendor/github.com/cloudflare/cfssl/helpers/BUILD
generated
vendored
3
vendor/github.com/cloudflare/cfssl/helpers/BUILD
generated
vendored
@@ -10,6 +10,9 @@ go_library(
|
|||||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/helpers/derhelpers:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/helpers/derhelpers:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/tls:go_default_library",
|
||||||
|
"//vendor/golang.org/x/crypto/ocsp:go_default_library",
|
||||||
"//vendor/golang.org/x/crypto/pkcs12:go_default_library",
|
"//vendor/golang.org/x/crypto/pkcs12:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
249
vendor/github.com/cloudflare/cfssl/helpers/helpers.go
generated
vendored
249
vendor/github.com/cloudflare/cfssl/helpers/helpers.go
generated
vendored
@@ -6,13 +6,23 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"os"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go"
|
||||||
|
cttls "github.com/google/certificate-transparency-go/tls"
|
||||||
|
"golang.org/x/crypto/ocsp"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -310,11 +320,23 @@ func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, e
|
|||||||
|
|
||||||
// LoadPEMCertPool loads a pool of PEM certificates from file.
|
// LoadPEMCertPool loads a pool of PEM certificates from file.
|
||||||
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
|
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
|
||||||
|
if certsFile == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
pemCerts, err := ioutil.ReadFile(certsFile)
|
pemCerts, err := ioutil.ReadFile(certsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return PEMToCertPool(pemCerts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PEMToCertPool concerts PEM certificates to a CertPool.
|
||||||
|
func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
|
||||||
|
if len(pemCerts) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
certPool := x509.NewCertPool()
|
certPool := x509.NewCertPool()
|
||||||
if !certPool.AppendCertsFromPEM(pemCerts) {
|
if !certPool.AppendCertsFromPEM(pemCerts) {
|
||||||
return nil, errors.New("failed to load cert pool")
|
return nil, errors.New("failed to load cert pool")
|
||||||
@@ -360,57 +382,12 @@ func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
|
|||||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
|
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckSignature verifies a signature made by the key on a CSR, such
|
|
||||||
// as on the CSR itself.
|
|
||||||
func CheckSignature(csr *x509.CertificateRequest, algo x509.SignatureAlgorithm, signed, signature []byte) error {
|
|
||||||
var hashType crypto.Hash
|
|
||||||
|
|
||||||
switch algo {
|
|
||||||
case x509.SHA1WithRSA, x509.ECDSAWithSHA1:
|
|
||||||
hashType = crypto.SHA1
|
|
||||||
case x509.SHA256WithRSA, x509.ECDSAWithSHA256:
|
|
||||||
hashType = crypto.SHA256
|
|
||||||
case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
|
|
||||||
hashType = crypto.SHA384
|
|
||||||
case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
|
|
||||||
hashType = crypto.SHA512
|
|
||||||
default:
|
|
||||||
return x509.ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hashType.Available() {
|
|
||||||
return x509.ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
h := hashType.New()
|
|
||||||
|
|
||||||
h.Write(signed)
|
|
||||||
digest := h.Sum(nil)
|
|
||||||
|
|
||||||
switch pub := csr.PublicKey.(type) {
|
|
||||||
case *rsa.PublicKey:
|
|
||||||
return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
|
|
||||||
case *ecdsa.PublicKey:
|
|
||||||
ecdsaSig := new(struct{ R, S *big.Int })
|
|
||||||
if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
|
|
||||||
return errors.New("x509: ECDSA signature contained zero or negative values")
|
|
||||||
}
|
|
||||||
if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
|
|
||||||
return errors.New("x509: ECDSA verification failure")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return x509.ErrUnsupportedAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
|
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
|
||||||
func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
|
func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
|
||||||
in = bytes.TrimSpace(in)
|
in = bytes.TrimSpace(in)
|
||||||
p, rest := pem.Decode(in)
|
p, rest := pem.Decode(in)
|
||||||
if p != nil {
|
if p != nil {
|
||||||
if p.Type != "CERTIFICATE REQUEST" {
|
if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
|
||||||
return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
|
return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +400,7 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error)
|
|||||||
return nil, rest, err
|
return nil, rest, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
|
err = csr.CheckSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, rest, err
|
return nil, rest, err
|
||||||
}
|
}
|
||||||
@@ -436,8 +413,10 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error)
|
|||||||
// locally.
|
// locally.
|
||||||
func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
||||||
block, _ := pem.Decode([]byte(csrPEM))
|
block, _ := pem.Decode([]byte(csrPEM))
|
||||||
der := block.Bytes
|
if block == nil {
|
||||||
csrObject, err := x509.ParseCertificateRequest(der)
|
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
|
||||||
|
}
|
||||||
|
csrObject, err := x509.ParseCertificateRequest(block.Bytes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -446,28 +425,28 @@ func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
|||||||
return csrObject, nil
|
return csrObject, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignerAlgo returns an X.509 signature algorithm corresponding to
|
// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
|
||||||
// the crypto.Hash provided from a crypto.Signer.
|
func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
||||||
func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
|
switch pub := priv.Public().(type) {
|
||||||
switch priv.Public().(type) {
|
|
||||||
case *rsa.PublicKey:
|
case *rsa.PublicKey:
|
||||||
switch h {
|
bitLength := pub.N.BitLen()
|
||||||
case crypto.SHA512:
|
switch {
|
||||||
|
case bitLength >= 4096:
|
||||||
return x509.SHA512WithRSA
|
return x509.SHA512WithRSA
|
||||||
case crypto.SHA384:
|
case bitLength >= 3072:
|
||||||
return x509.SHA384WithRSA
|
return x509.SHA384WithRSA
|
||||||
case crypto.SHA256:
|
case bitLength >= 2048:
|
||||||
return x509.SHA256WithRSA
|
return x509.SHA256WithRSA
|
||||||
default:
|
default:
|
||||||
return x509.SHA1WithRSA
|
return x509.SHA1WithRSA
|
||||||
}
|
}
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
switch h {
|
switch pub.Curve {
|
||||||
case crypto.SHA512:
|
case elliptic.P521():
|
||||||
return x509.ECDSAWithSHA512
|
return x509.ECDSAWithSHA512
|
||||||
case crypto.SHA384:
|
case elliptic.P384():
|
||||||
return x509.ECDSAWithSHA384
|
return x509.ECDSAWithSHA384
|
||||||
case crypto.SHA256:
|
case elliptic.P256():
|
||||||
return x509.ECDSAWithSHA256
|
return x509.ECDSAWithSHA256
|
||||||
default:
|
default:
|
||||||
return x509.ECDSAWithSHA1
|
return x509.ECDSAWithSHA1
|
||||||
@@ -476,3 +455,149 @@ func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
|
|||||||
return x509.UnknownSignatureAlgorithm
|
return x509.UnknownSignatureAlgorithm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadClientCertificate load key/certificate from pem files
|
||||||
|
func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
|
||||||
|
if certFile != "" && keyFile != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debug("Client certificate loaded ")
|
||||||
|
return &cert, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTLSConfig creates a tls.Config object from certs and roots
|
||||||
|
func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
|
||||||
|
var certs []tls.Certificate
|
||||||
|
if cert != nil {
|
||||||
|
certs = []tls.Certificate{*cert}
|
||||||
|
}
|
||||||
|
return &tls.Config{
|
||||||
|
Certificates: certs,
|
||||||
|
RootCAs: remoteCAs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeSCTList serializes a list of SCTs.
|
||||||
|
func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, sct := range sctList {
|
||||||
|
sct, err := cttls.Marshal(sct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
binary.Write(&buf, binary.BigEndian, uint16(len(sct)))
|
||||||
|
buf.Write(sct)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sctListLengthField = make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(sctListLengthField, uint16(buf.Len()))
|
||||||
|
return bytes.Join([][]byte{sctListLengthField, buf.Bytes()}, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeserializeSCTList deserializes a list of SCTs.
|
||||||
|
func DeserializeSCTList(serializedSCTList []byte) (*[]ct.SignedCertificateTimestamp, error) {
|
||||||
|
sctList := new([]ct.SignedCertificateTimestamp)
|
||||||
|
sctReader := bytes.NewBuffer(serializedSCTList)
|
||||||
|
|
||||||
|
var sctListLen uint16
|
||||||
|
err := binary.Read(sctReader, binary.BigEndian, &sctListLen)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown,
|
||||||
|
errors.New("serialized SCT list could not be read"))
|
||||||
|
}
|
||||||
|
return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
|
}
|
||||||
|
if sctReader.Len() != int(sctListLen) {
|
||||||
|
return sctList, errors.New("SCT length field and SCT length don't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
for err != io.EOF {
|
||||||
|
var sctLen uint16
|
||||||
|
err = binary.Read(sctReader, binary.BigEndian, &sctLen)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return sctList, nil
|
||||||
|
}
|
||||||
|
return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sctReader.Len() < int(sctLen) {
|
||||||
|
return sctList, errors.New("SCT length field and SCT length don't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedSCT := sctReader.Next(int(sctLen))
|
||||||
|
var sct ct.SignedCertificateTimestamp
|
||||||
|
if _, err := cttls.Unmarshal(serializedSCT, &sct); err != nil {
|
||||||
|
return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
temp := append(*sctList, sct)
|
||||||
|
sctList = &temp
|
||||||
|
}
|
||||||
|
|
||||||
|
return sctList, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response,
|
||||||
|
// returning an empty list if the SCT extension was not found or could not be
|
||||||
|
// unmarshalled.
|
||||||
|
func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTimestamp, error) {
|
||||||
|
// This loop finds the SCTListExtension in the OCSP response.
|
||||||
|
var SCTListExtension, ext pkix.Extension
|
||||||
|
for _, ext = range response.Extensions {
|
||||||
|
// sctExtOid is the ObjectIdentifier of a Signed Certificate Timestamp.
|
||||||
|
sctExtOid := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}
|
||||||
|
if ext.Id.Equal(sctExtOid) {
|
||||||
|
SCTListExtension = ext
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This code block extracts the sctList from the SCT extension.
|
||||||
|
var emptySCTList []ct.SignedCertificateTimestamp
|
||||||
|
sctList := &emptySCTList
|
||||||
|
var err error
|
||||||
|
if numBytes := len(SCTListExtension.Value); numBytes != 0 {
|
||||||
|
serializedSCTList := new([]byte)
|
||||||
|
rest := make([]byte, numBytes)
|
||||||
|
copy(rest, SCTListExtension.Value)
|
||||||
|
for len(rest) != 0 {
|
||||||
|
rest, err = asn1.Unmarshal(rest, serializedSCTList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sctList, err = DeserializeSCTList(*serializedSCTList)
|
||||||
|
}
|
||||||
|
return *sctList, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadBytes reads a []byte either from a file or an environment variable.
|
||||||
|
// If valFile has a prefix of 'env:', the []byte is read from the environment
|
||||||
|
// using the subsequent name. If the prefix is 'file:' the []byte is read from
|
||||||
|
// the subsequent file. If no prefix is provided, valFile is assumed to be a
|
||||||
|
// file path.
|
||||||
|
func ReadBytes(valFile string) ([]byte, error) {
|
||||||
|
switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
|
||||||
|
case 1:
|
||||||
|
return ioutil.ReadFile(valFile)
|
||||||
|
case 2:
|
||||||
|
switch splitVal[0] {
|
||||||
|
case "env":
|
||||||
|
return []byte(os.Getenv(splitVal[1])), nil
|
||||||
|
case "file":
|
||||||
|
return ioutil.ReadFile(splitVal[1])
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("multiple prefixes: %s",
|
||||||
|
strings.Join(splitVal[:len(splitVal)-1], ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
36
vendor/github.com/cloudflare/cfssl/log/log.go
generated
vendored
36
vendor/github.com/cloudflare/cfssl/log/log.go
generated
vendored
@@ -6,7 +6,6 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -45,12 +44,12 @@ var Level = LevelInfo
|
|||||||
//
|
//
|
||||||
// SyslogWriter is satisfied by *syslog.Writer.
|
// SyslogWriter is satisfied by *syslog.Writer.
|
||||||
type SyslogWriter interface {
|
type SyslogWriter interface {
|
||||||
Debug(string) error
|
Debug(string)
|
||||||
Info(string) error
|
Info(string)
|
||||||
Warning(string) error
|
Warning(string)
|
||||||
Err(string) error
|
Err(string)
|
||||||
Crit(string) error
|
Crit(string)
|
||||||
Emerg(string) error
|
Emerg(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// syslogWriter stores the SetLogger() parameter.
|
// syslogWriter stores the SetLogger() parameter.
|
||||||
@@ -63,33 +62,22 @@ func SetLogger(logger SyslogWriter) {
|
|||||||
syslogWriter = logger
|
syslogWriter = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Only define loglevel flag once.
|
|
||||||
if flag.Lookup("loglevel") == nil {
|
|
||||||
flag.IntVar(&Level, "loglevel", LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func print(l int, msg string) {
|
func print(l int, msg string) {
|
||||||
if l >= Level {
|
if l >= Level {
|
||||||
if syslogWriter != nil {
|
if syslogWriter != nil {
|
||||||
var err error
|
|
||||||
switch l {
|
switch l {
|
||||||
case LevelDebug:
|
case LevelDebug:
|
||||||
err = syslogWriter.Debug(msg)
|
syslogWriter.Debug(msg)
|
||||||
case LevelInfo:
|
case LevelInfo:
|
||||||
err = syslogWriter.Info(msg)
|
syslogWriter.Info(msg)
|
||||||
case LevelWarning:
|
case LevelWarning:
|
||||||
err = syslogWriter.Warning(msg)
|
syslogWriter.Warning(msg)
|
||||||
case LevelError:
|
case LevelError:
|
||||||
err = syslogWriter.Err(msg)
|
syslogWriter.Err(msg)
|
||||||
case LevelCritical:
|
case LevelCritical:
|
||||||
err = syslogWriter.Crit(msg)
|
syslogWriter.Crit(msg)
|
||||||
case LevelFatal:
|
case LevelFatal:
|
||||||
err = syslogWriter.Emerg(msg)
|
syslogWriter.Emerg(msg)
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unable to write syslog: %v for msg: %s\n", err, msg)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[%s] %s", levelPrefix[l], msg)
|
log.Printf("[%s] %s", levelPrefix[l], msg)
|
||||||
|
|||||||
1
vendor/github.com/cloudflare/cfssl/signer/BUILD
generated
vendored
1
vendor/github.com/cloudflare/cfssl/signer/BUILD
generated
vendored
@@ -10,7 +10,6 @@ go_library(
|
|||||||
"//vendor/github.com/cloudflare/cfssl/config:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/config:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
|
||||||
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
6
vendor/github.com/cloudflare/cfssl/signer/local/BUILD
generated
vendored
6
vendor/github.com/cloudflare/cfssl/signer/local/BUILD
generated
vendored
@@ -13,8 +13,10 @@ go_library(
|
|||||||
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||||
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
||||||
"//vendor/github.com/google/certificate-transparency/go:go_default_library",
|
"//vendor/github.com/google/certificate-transparency-go:go_default_library",
|
||||||
"//vendor/github.com/google/certificate-transparency/go/client:go_default_library",
|
"//vendor/github.com/google/certificate-transparency-go/client:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/jsonclient:go_default_library",
|
||||||
|
"//vendor/golang.org/x/net/context:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
118
vendor/github.com/cloudflare/cfssl/signer/local/local.go
generated
vendored
118
vendor/github.com/cloudflare/cfssl/signer/local/local.go
generated
vendored
@@ -8,14 +8,13 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -26,8 +25,10 @@ import (
|
|||||||
"github.com/cloudflare/cfssl/info"
|
"github.com/cloudflare/cfssl/info"
|
||||||
"github.com/cloudflare/cfssl/log"
|
"github.com/cloudflare/cfssl/log"
|
||||||
"github.com/cloudflare/cfssl/signer"
|
"github.com/cloudflare/cfssl/signer"
|
||||||
"github.com/google/certificate-transparency/go"
|
"github.com/google/certificate-transparency-go"
|
||||||
"github.com/google/certificate-transparency/go/client"
|
"github.com/google/certificate-transparency-go/client"
|
||||||
|
"github.com/google/certificate-transparency-go/jsonclient"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Signer contains a signer that uses the standard library to
|
// Signer contains a signer that uses the standard library to
|
||||||
@@ -65,12 +66,12 @@ func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.Signatur
|
|||||||
// and a caKey file, both PEM encoded.
|
// and a caKey file, both PEM encoded.
|
||||||
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
|
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
|
||||||
log.Debug("Loading CA: ", caFile)
|
log.Debug("Loading CA: ", caFile)
|
||||||
ca, err := ioutil.ReadFile(caFile)
|
ca, err := helpers.ReadBytes(caFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debug("Loading CA key: ", caKeyFile)
|
log.Debug("Loading CA key: ", caKeyFile)
|
||||||
cakey, err := ioutil.ReadFile(caKeyFile)
|
cakey, err := helpers.ReadBytes(caKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
|
return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
|
||||||
}
|
}
|
||||||
@@ -95,12 +96,7 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
|
|||||||
return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
|
return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
|
func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
|
||||||
err = signer.FillTemplate(template, s.policy.Default, profile)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var initRoot bool
|
var initRoot bool
|
||||||
if s.ca == nil {
|
if s.ca == nil {
|
||||||
if !template.IsCA {
|
if !template.IsCA {
|
||||||
@@ -111,11 +107,6 @@ func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile
|
|||||||
template.EmailAddresses = nil
|
template.EmailAddresses = nil
|
||||||
s.ca = template
|
s.ca = template
|
||||||
initRoot = true
|
initRoot = true
|
||||||
template.MaxPathLen = signer.MaxPathLen
|
|
||||||
} else if template.IsCA {
|
|
||||||
template.MaxPathLen = 1
|
|
||||||
template.DNSNames = nil
|
|
||||||
template.EmailAddresses = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
|
derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
|
||||||
@@ -203,9 +194,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
|
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Type != "CERTIFICATE REQUEST" {
|
if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
|
||||||
return nil, cferr.Wrap(cferr.CSRError,
|
return nil, cferr.Wrap(cferr.CSRError,
|
||||||
cferr.BadRequest, errors.New("not a certificate or csr"))
|
cferr.BadRequest, errors.New("not a csr"))
|
||||||
}
|
}
|
||||||
|
|
||||||
csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes)
|
csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes)
|
||||||
@@ -243,6 +234,29 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.CRLOverride != "" {
|
||||||
|
safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
|
||||||
|
}
|
||||||
|
|
||||||
|
if safeTemplate.IsCA {
|
||||||
|
if !profile.CAConstraint.IsCA {
|
||||||
|
log.Error("local signer policy disallows issuing CA certificate")
|
||||||
|
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ca != nil && s.ca.MaxPathLen > 0 {
|
||||||
|
if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
|
||||||
|
log.Error("local signer certificate disallows CA MaxPathLen extending")
|
||||||
|
// do not sign a cert with pathlen > current
|
||||||
|
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
|
||||||
|
}
|
||||||
|
} else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
|
||||||
|
log.Error("local signer certificate disallows issuing CA certificate")
|
||||||
|
// signer has pathlen of 0, do not sign more intermediate CAs
|
||||||
|
return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OverrideHosts(&safeTemplate, req.Hosts)
|
OverrideHosts(&safeTemplate, req.Hosts)
|
||||||
safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
|
safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
|
||||||
|
|
||||||
@@ -250,17 +264,17 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
if profile.NameWhitelist != nil {
|
if profile.NameWhitelist != nil {
|
||||||
if safeTemplate.Subject.CommonName != "" {
|
if safeTemplate.Subject.CommonName != "" {
|
||||||
if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil {
|
if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil {
|
||||||
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
|
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, name := range safeTemplate.DNSNames {
|
for _, name := range safeTemplate.DNSNames {
|
||||||
if profile.NameWhitelist.Find([]byte(name)) == nil {
|
if profile.NameWhitelist.Find([]byte(name)) == nil {
|
||||||
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
|
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, name := range safeTemplate.EmailAddresses {
|
for _, name := range safeTemplate.EmailAddresses {
|
||||||
if profile.NameWhitelist.Find([]byte(name)) == nil {
|
if profile.NameWhitelist.Find([]byte(name)) == nil {
|
||||||
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
|
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,6 +326,15 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var distPoints = safeTemplate.CRLDistributionPoints
|
||||||
|
err = signer.FillTemplate(&safeTemplate, s.policy.Default, profile, req.NotBefore, req.NotAfter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if distPoints != nil && len(distPoints) > 0 {
|
||||||
|
safeTemplate.CRLDistributionPoints = distPoints
|
||||||
|
}
|
||||||
|
|
||||||
var certTBS = safeTemplate
|
var certTBS = safeTemplate
|
||||||
|
|
||||||
if len(profile.CTLogServers) > 0 {
|
if len(profile.CTLogServers) > 0 {
|
||||||
@@ -319,20 +342,24 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
|
var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
|
||||||
var poisonedPreCert = certTBS
|
var poisonedPreCert = certTBS
|
||||||
poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
|
poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
|
||||||
cert, err = s.sign(&poisonedPreCert, profile)
|
cert, err = s.sign(&poisonedPreCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
derCert, _ := pem.Decode(cert)
|
derCert, _ := pem.Decode(cert)
|
||||||
prechain := []ct.ASN1Cert{derCert.Bytes, s.ca.Raw}
|
prechain := []ct.ASN1Cert{{Data: derCert.Bytes}, {Data: s.ca.Raw}}
|
||||||
var sctList []ct.SignedCertificateTimestamp
|
var sctList []ct.SignedCertificateTimestamp
|
||||||
|
|
||||||
for _, server := range profile.CTLogServers {
|
for _, server := range profile.CTLogServers {
|
||||||
log.Infof("submitting poisoned precertificate to %s", server)
|
log.Infof("submitting poisoned precertificate to %s", server)
|
||||||
var ctclient = client.New(server)
|
ctclient, err := client.New(server, nil, jsonclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
|
||||||
|
}
|
||||||
var resp *ct.SignedCertificateTimestamp
|
var resp *ct.SignedCertificateTimestamp
|
||||||
resp, err = ctclient.AddPreChain(prechain)
|
ctx := context.Background()
|
||||||
|
resp, err = ctclient.AddPreChain(ctx, prechain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
|
return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
|
||||||
}
|
}
|
||||||
@@ -340,7 +367,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var serializedSCTList []byte
|
var serializedSCTList []byte
|
||||||
serializedSCTList, err = serializeSCTList(sctList)
|
serializedSCTList, err = helpers.SerializeSCTList(sctList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||||
}
|
}
|
||||||
@@ -355,17 +382,22 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
|
certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
|
||||||
}
|
}
|
||||||
var signedCert []byte
|
var signedCert []byte
|
||||||
signedCert, err = s.sign(&certTBS, profile)
|
signedCert, err = s.sign(&certTBS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the AKI from signedCert. This is required to support Go 1.9+.
|
||||||
|
// In prior versions of Go, x509.CreateCertificate updated the
|
||||||
|
// AuthorityKeyId of certTBS.
|
||||||
|
parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
|
||||||
|
|
||||||
if s.dbAccessor != nil {
|
if s.dbAccessor != nil {
|
||||||
var certRecord = certdb.CertificateRecord{
|
var certRecord = certdb.CertificateRecord{
|
||||||
Serial: certTBS.SerialNumber.String(),
|
Serial: certTBS.SerialNumber.String(),
|
||||||
// this relies on the specific behavior of x509.CreateCertificate
|
// this relies on the specific behavior of x509.CreateCertificate
|
||||||
// which updates certTBS AuthorityKeyId from the signer's SubjectKeyId
|
// which sets the AuthorityKeyId from the signer's SubjectKeyId
|
||||||
AKI: hex.EncodeToString(certTBS.AuthorityKeyId),
|
AKI: hex.EncodeToString(parsedCert.AuthorityKeyId),
|
||||||
CALabel: req.Label,
|
CALabel: req.Label,
|
||||||
Status: "good",
|
Status: "good",
|
||||||
Expiry: certTBS.NotAfter,
|
Expiry: certTBS.NotAfter,
|
||||||
@@ -382,22 +414,6 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||||||
return signedCert, nil
|
return signedCert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, sct := range sctList {
|
|
||||||
sct, err := ct.SerializeSCT(sct)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
binary.Write(&buf, binary.BigEndian, uint16(len(sct)))
|
|
||||||
buf.Write(sct)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sctListLengthField = make([]byte, 2)
|
|
||||||
binary.BigEndian.PutUint16(sctListLengthField, uint16(buf.Len()))
|
|
||||||
return bytes.Join([][]byte{sctListLengthField, buf.Bytes()}, nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info return a populated info.Resp struct or an error.
|
// Info return a populated info.Resp struct or an error.
|
||||||
func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) {
|
func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) {
|
||||||
cert, err := s.Certificate(req.Label, req.Profile)
|
cert, err := s.Certificate(req.Label, req.Profile)
|
||||||
@@ -441,6 +457,16 @@ func (s *Signer) SetDBAccessor(dba certdb.Accessor) {
|
|||||||
s.dbAccessor = dba
|
s.dbAccessor = dba
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDBAccessor returns the signers' cert db accessor
|
||||||
|
func (s *Signer) GetDBAccessor() certdb.Accessor {
|
||||||
|
return s.dbAccessor
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReqModifier does nothing for local
|
||||||
|
func (s *Signer) SetReqModifier(func(*http.Request, []byte)) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
// Policy returns the signer's policy.
|
// Policy returns the signer's policy.
|
||||||
func (s *Signer) Policy() *config.Signing {
|
func (s *Signer) Policy() *config.Signing {
|
||||||
return s.policy
|
return s.policy
|
||||||
|
|||||||
97
vendor/github.com/cloudflare/cfssl/signer/signer.go
generated
vendored
97
vendor/github.com/cloudflare/cfssl/signer/signer.go
generated
vendored
@@ -12,6 +12,7 @@ import (
|
|||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -19,13 +20,9 @@ import (
|
|||||||
"github.com/cloudflare/cfssl/config"
|
"github.com/cloudflare/cfssl/config"
|
||||||
"github.com/cloudflare/cfssl/csr"
|
"github.com/cloudflare/cfssl/csr"
|
||||||
cferr "github.com/cloudflare/cfssl/errors"
|
cferr "github.com/cloudflare/cfssl/errors"
|
||||||
"github.com/cloudflare/cfssl/helpers"
|
|
||||||
"github.com/cloudflare/cfssl/info"
|
"github.com/cloudflare/cfssl/info"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MaxPathLen is the default path length for a new CA certificate.
|
|
||||||
var MaxPathLen = 2
|
|
||||||
|
|
||||||
// Subject contains the information that should be used to override the
|
// Subject contains the information that should be used to override the
|
||||||
// subject information when signing a certificate.
|
// subject information when signing a certificate.
|
||||||
type Subject struct {
|
type Subject struct {
|
||||||
@@ -54,9 +51,19 @@ type SignRequest struct {
|
|||||||
Request string `json:"certificate_request"`
|
Request string `json:"certificate_request"`
|
||||||
Subject *Subject `json:"subject,omitempty"`
|
Subject *Subject `json:"subject,omitempty"`
|
||||||
Profile string `json:"profile"`
|
Profile string `json:"profile"`
|
||||||
|
CRLOverride string `json:"crl_override"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Serial *big.Int `json:"serial,omitempty"`
|
Serial *big.Int `json:"serial,omitempty"`
|
||||||
Extensions []Extension `json:"extensions,omitempty"`
|
Extensions []Extension `json:"extensions,omitempty"`
|
||||||
|
// If provided, NotBefore will be used without modification (except
|
||||||
|
// for canonicalization) as the value of the notBefore field of the
|
||||||
|
// certificate. In particular no backdating adjustment will be made
|
||||||
|
// when NotBefore is provided.
|
||||||
|
NotBefore time.Time
|
||||||
|
// If provided, NotAfter will be used without modification (except
|
||||||
|
// for canonicalization) as the value of the notAfter field of the
|
||||||
|
// certificate.
|
||||||
|
NotAfter time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendIf appends to a if s is not an empty string.
|
// appendIf appends to a if s is not an empty string.
|
||||||
@@ -98,9 +105,11 @@ type Signer interface {
|
|||||||
Info(info.Req) (*info.Resp, error)
|
Info(info.Req) (*info.Resp, error)
|
||||||
Policy() *config.Signing
|
Policy() *config.Signing
|
||||||
SetDBAccessor(certdb.Accessor)
|
SetDBAccessor(certdb.Accessor)
|
||||||
|
GetDBAccessor() certdb.Accessor
|
||||||
SetPolicy(*config.Signing)
|
SetPolicy(*config.Signing)
|
||||||
SigAlgo() x509.SignatureAlgorithm
|
SigAlgo() x509.SignatureAlgorithm
|
||||||
Sign(req SignRequest) (cert []byte, err error)
|
Sign(req SignRequest) (cert []byte, err error)
|
||||||
|
SetReqModifier(func(*http.Request, []byte))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile gets the specific profile from the signer
|
// Profile gets the specific profile from the signer
|
||||||
@@ -157,26 +166,46 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
|||||||
// ParseCertificateRequest takes an incoming certificate request and
|
// ParseCertificateRequest takes an incoming certificate request and
|
||||||
// builds a certificate template from it.
|
// builds a certificate template from it.
|
||||||
func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
|
func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
|
||||||
csr, err := x509.ParseCertificateRequest(csrBytes)
|
csrv, err := x509.ParseCertificateRequest(csrBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
|
err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
|
err = csrv.CheckSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
|
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
template = &x509.Certificate{
|
template = &x509.Certificate{
|
||||||
Subject: csr.Subject,
|
Subject: csrv.Subject,
|
||||||
PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
|
PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
|
||||||
PublicKey: csr.PublicKey,
|
PublicKey: csrv.PublicKey,
|
||||||
SignatureAlgorithm: s.SigAlgo(),
|
SignatureAlgorithm: s.SigAlgo(),
|
||||||
DNSNames: csr.DNSNames,
|
DNSNames: csrv.DNSNames,
|
||||||
IPAddresses: csr.IPAddresses,
|
IPAddresses: csrv.IPAddresses,
|
||||||
EmailAddresses: csr.EmailAddresses,
|
EmailAddresses: csrv.EmailAddresses,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, val := range csrv.Extensions {
|
||||||
|
// Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9)
|
||||||
|
// extension and append to template if necessary
|
||||||
|
if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
|
||||||
|
var constraints csr.BasicConstraints
|
||||||
|
var rest []byte
|
||||||
|
|
||||||
|
if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
|
||||||
|
return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints"))
|
||||||
|
}
|
||||||
|
|
||||||
|
template.BasicConstraintsValid = true
|
||||||
|
template.IsCA = constraints.IsCA
|
||||||
|
template.MaxPathLen = constraints.MaxPathLen
|
||||||
|
template.MaxPathLenZero = template.MaxPathLen == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -211,17 +240,19 @@ func ComputeSKI(template *x509.Certificate) ([]byte, error) {
|
|||||||
// the certificate template as possible from the profiles and current
|
// the certificate template as possible from the profiles and current
|
||||||
// template. It fills in the key uses, expiration, revocation URLs
|
// template. It fills in the key uses, expiration, revocation URLs
|
||||||
// and SKI.
|
// and SKI.
|
||||||
func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile) error {
|
func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile, notBefore time.Time, notAfter time.Time) error {
|
||||||
ski, err := ComputeSKI(template)
|
ski, err := ComputeSKI(template)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
eku []x509.ExtKeyUsage
|
eku []x509.ExtKeyUsage
|
||||||
ku x509.KeyUsage
|
ku x509.KeyUsage
|
||||||
backdate time.Duration
|
backdate time.Duration
|
||||||
expiry time.Duration
|
expiry time.Duration
|
||||||
notBefore time.Time
|
|
||||||
notAfter time.Time
|
|
||||||
crlURL, ocspURL string
|
crlURL, ocspURL string
|
||||||
|
issuerURL = profile.IssuerURL
|
||||||
)
|
)
|
||||||
|
|
||||||
// The third value returned from Usages is a list of unknown key usages.
|
// The third value returned from Usages is a list of unknown key usages.
|
||||||
@@ -229,7 +260,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
|
|||||||
// here.
|
// here.
|
||||||
ku, eku, _ = profile.Usages()
|
ku, eku, _ = profile.Usages()
|
||||||
if profile.IssuerURL == nil {
|
if profile.IssuerURL == nil {
|
||||||
profile.IssuerURL = defaultProfile.IssuerURL
|
issuerURL = defaultProfile.IssuerURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if ku == 0 && len(eku) == 0 {
|
if ku == 0 && len(eku) == 0 {
|
||||||
@@ -246,30 +277,44 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
|
|||||||
if ocspURL = profile.OCSP; ocspURL == "" {
|
if ocspURL = profile.OCSP; ocspURL == "" {
|
||||||
ocspURL = defaultProfile.OCSP
|
ocspURL = defaultProfile.OCSP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if notBefore.IsZero() {
|
||||||
|
if !profile.NotBefore.IsZero() {
|
||||||
|
notBefore = profile.NotBefore
|
||||||
|
} else {
|
||||||
if backdate = profile.Backdate; backdate == 0 {
|
if backdate = profile.Backdate; backdate == 0 {
|
||||||
backdate = -5 * time.Minute
|
backdate = -5 * time.Minute
|
||||||
} else {
|
} else {
|
||||||
backdate = -1 * profile.Backdate
|
backdate = -1 * profile.Backdate
|
||||||
}
|
}
|
||||||
|
notBefore = time.Now().Round(time.Minute).Add(backdate)
|
||||||
if !profile.NotBefore.IsZero() {
|
|
||||||
notBefore = profile.NotBefore.UTC()
|
|
||||||
} else {
|
|
||||||
notBefore = time.Now().Round(time.Minute).Add(backdate).UTC()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
notBefore = notBefore.UTC()
|
||||||
|
|
||||||
|
if notAfter.IsZero() {
|
||||||
if !profile.NotAfter.IsZero() {
|
if !profile.NotAfter.IsZero() {
|
||||||
notAfter = profile.NotAfter.UTC()
|
notAfter = profile.NotAfter
|
||||||
} else {
|
} else {
|
||||||
notAfter = notBefore.Add(expiry).UTC()
|
notAfter = notBefore.Add(expiry)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
notAfter = notAfter.UTC()
|
||||||
|
|
||||||
template.NotBefore = notBefore
|
template.NotBefore = notBefore
|
||||||
template.NotAfter = notAfter
|
template.NotAfter = notAfter
|
||||||
template.KeyUsage = ku
|
template.KeyUsage = ku
|
||||||
template.ExtKeyUsage = eku
|
template.ExtKeyUsage = eku
|
||||||
template.BasicConstraintsValid = true
|
template.BasicConstraintsValid = true
|
||||||
template.IsCA = profile.CA
|
template.IsCA = profile.CAConstraint.IsCA
|
||||||
|
if template.IsCA {
|
||||||
|
template.MaxPathLen = profile.CAConstraint.MaxPathLen
|
||||||
|
if template.MaxPathLen == 0 {
|
||||||
|
template.MaxPathLenZero = profile.CAConstraint.MaxPathLenZero
|
||||||
|
}
|
||||||
|
template.DNSNames = nil
|
||||||
|
template.EmailAddresses = nil
|
||||||
|
}
|
||||||
template.SubjectKeyId = ski
|
template.SubjectKeyId = ski
|
||||||
|
|
||||||
if ocspURL != "" {
|
if ocspURL != "" {
|
||||||
@@ -279,8 +324,8 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
|
|||||||
template.CRLDistributionPoints = []string{crlURL}
|
template.CRLDistributionPoints = []string{crlURL}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(profile.IssuerURL) != 0 {
|
if len(issuerURL) != 0 {
|
||||||
template.IssuingCertificateURL = profile.IssuerURL
|
template.IssuingCertificateURL = issuerURL
|
||||||
}
|
}
|
||||||
if len(profile.Policies) != 0 {
|
if len(profile.Policies) != 0 {
|
||||||
err = addPolicies(template, profile.Policies)
|
err = addPolicies(template, profile.Policies)
|
||||||
|
|||||||
24
vendor/github.com/google/certificate-transparency-go/.gitignore
generated
vendored
Normal file
24
vendor/github.com/google/certificate-transparency-go/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
*.iml
|
||||||
|
*.swo
|
||||||
|
*.swp
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.backup
|
||||||
|
*~
|
||||||
|
/.idea
|
||||||
|
/certcheck
|
||||||
|
/chainfix
|
||||||
|
/coverage.txt
|
||||||
|
/createtree
|
||||||
|
/crlcheck
|
||||||
|
/ctclient
|
||||||
|
/ct_server
|
||||||
|
/ct_hammer
|
||||||
|
/data
|
||||||
|
/dumpscts
|
||||||
|
/etcdiscover
|
||||||
|
/gossip_server
|
||||||
|
/preloader
|
||||||
|
/scanlog
|
||||||
|
/trillian_log_server
|
||||||
|
/trillian_log_signer
|
||||||
|
/trillian.json
|
||||||
66
vendor/github.com/google/certificate-transparency-go/.travis.yml
generated
vendored
Normal file
66
vendor/github.com/google/certificate-transparency-go/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
os: linux
|
||||||
|
go: 1.9
|
||||||
|
|
||||||
|
env:
|
||||||
|
- GOFLAGS=
|
||||||
|
- GOFLAGS=-race
|
||||||
|
- GOFLAGS= WITH_ETCD=true
|
||||||
|
- GOFLAGS=-race WITH_ETCD=true
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
install:
|
||||||
|
- |
|
||||||
|
if [ ! -d $HOME/gopath/src/github.com/google ]; then
|
||||||
|
mkdir -p $HOME/gopath/src/github.com/google
|
||||||
|
ln -s $TRAVIS_BUILD_DIR $HOME/gopath/src/github.com/google/certificate-transparency-go
|
||||||
|
fi
|
||||||
|
- mkdir ../protoc
|
||||||
|
- |
|
||||||
|
(
|
||||||
|
cd ../protoc
|
||||||
|
wget https://github.com/google/protobuf/releases/download/v3.2.0/protoc-3.2.0-${TRAVIS_OS_NAME}-x86_64.zip
|
||||||
|
unzip protoc-3.2.0-${TRAVIS_OS_NAME}-x86_64.zip
|
||||||
|
)
|
||||||
|
- export PATH=$(pwd)/../protoc/bin:$PATH
|
||||||
|
- go get -d -t ./...
|
||||||
|
- go get github.com/alecthomas/gometalinter
|
||||||
|
- gometalinter --install
|
||||||
|
- go get -u github.com/golang/protobuf/proto
|
||||||
|
- go get -u github.com/golang/protobuf/protoc-gen-go
|
||||||
|
- go install github.com/golang/mock/mockgen
|
||||||
|
# install vendored etcd binary
|
||||||
|
- go install ./vendor/github.com/coreos/etcd/cmd/etcd
|
||||||
|
- go install ./vendor/github.com/coreos/etcd/cmd/etcdctl
|
||||||
|
- pushd ${GOPATH}/src/github.com/google/trillian
|
||||||
|
- go get -d -t ./...
|
||||||
|
- popd
|
||||||
|
|
||||||
|
script:
|
||||||
|
- set -e
|
||||||
|
- export TRILLIAN_SQL_DRIVER=mysql
|
||||||
|
- cd $HOME/gopath/src/github.com/google/certificate-transparency-go
|
||||||
|
- ./scripts/presubmit.sh ${PRESUBMIT_OPTS}
|
||||||
|
- |
|
||||||
|
# Check re-generation didn't change anything
|
||||||
|
status=$(git status --porcelain | grep -v coverage) || :
|
||||||
|
if [[ -n ${status} ]]; then
|
||||||
|
echo "Regenerated files differ from checked-in versions: ${status}"
|
||||||
|
git status
|
||||||
|
git diff
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [[ "${WITH_ETCD}" == "true" ]]; then
|
||||||
|
export ETCD_DIR="${GOPATH}/bin"
|
||||||
|
fi
|
||||||
|
- ./trillian/integration/integration_test.sh
|
||||||
|
- HAMMER_OPTS="--operations=1500" ./trillian/integration/ct_hammer_test.sh
|
||||||
|
- set +e
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- cp /tmp/coverage.txt .
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
@@ -10,13 +10,17 @@
|
|||||||
|
|
||||||
Comodo CA Limited
|
Comodo CA Limited
|
||||||
Ed Maste <emaste@freebsd.org>
|
Ed Maste <emaste@freebsd.org>
|
||||||
|
Fiaz Hossain <fiaz.hossain@salesforce.com>
|
||||||
Google Inc.
|
Google Inc.
|
||||||
|
Internet Security Research Group
|
||||||
Jeff Trawick <trawick@gmail.com>
|
Jeff Trawick <trawick@gmail.com>
|
||||||
Katriel Cohn-Gordon <katriel.cohn-gordon@cybersecurity.ox.ac.uk>
|
Katriel Cohn-Gordon <katriel.cohn-gordon@cybersecurity.ox.ac.uk>
|
||||||
|
Laël Cellier <lael.cellier@gmail.com>
|
||||||
Mark Schloesser <ms@mwcollect.org>
|
Mark Schloesser <ms@mwcollect.org>
|
||||||
NORDUnet A/S
|
NORDUnet A/S
|
||||||
Nicholas Galbreath <nickg@client9.com>
|
Nicholas Galbreath <nickg@client9.com>
|
||||||
Oliver Weidner <Oliver.Weidner@gmail.com>
|
Oliver Weidner <Oliver.Weidner@gmail.com>
|
||||||
|
PrimeKey Solutions AB
|
||||||
Ruslan Kovalov <ruslan.kovalyov@gmail.com>
|
Ruslan Kovalov <ruslan.kovalyov@gmail.com>
|
||||||
Venafi, Inc.
|
Venafi, Inc.
|
||||||
Vladimir Rutsky <vladimir@rutsky.org>
|
Vladimir Rutsky <vladimir@rutsky.org>
|
||||||
37
vendor/github.com/google/certificate-transparency-go/BUILD
generated
vendored
Normal file
37
vendor/github.com/google/certificate-transparency-go/BUILD
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"serialization.go",
|
||||||
|
"signatures.go",
|
||||||
|
"types.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/google/certificate-transparency-go",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/tls:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/x509:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/asn1:all-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/client:all-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/jsonclient:all-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/tls:all-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/x509:all-srcs",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
58
vendor/github.com/google/certificate-transparency-go/CONTRIBUTING.md
generated
vendored
Normal file
58
vendor/github.com/google/certificate-transparency-go/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# How to contribute #
|
||||||
|
|
||||||
|
We'd love to accept your patches and contributions to this project. There are
|
||||||
|
a just a few small guidelines you need to follow.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributor License Agreement ##
|
||||||
|
|
||||||
|
Contributions to any Google project must be accompanied by a Contributor
|
||||||
|
License Agreement. This is not a copyright **assignment**, it simply gives
|
||||||
|
Google permission to use and redistribute your contributions as part of the
|
||||||
|
project.
|
||||||
|
|
||||||
|
* If you are an individual writing original source code and you're sure you
|
||||||
|
own the intellectual property, then you'll need to sign an [individual
|
||||||
|
CLA][].
|
||||||
|
|
||||||
|
* If you work for a company that wants to allow you to contribute your work,
|
||||||
|
then you'll need to sign a [corporate CLA][].
|
||||||
|
|
||||||
|
You generally only need to submit a CLA once, so if you've already submitted
|
||||||
|
one (even if it was for a different project), you probably don't need to do it
|
||||||
|
again.
|
||||||
|
|
||||||
|
[individual CLA]: https://developers.google.com/open-source/cla/individual
|
||||||
|
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
|
||||||
|
|
||||||
|
Once your CLA is submitted (or if you already submitted one for
|
||||||
|
another Google project), make a commit adding yourself to the
|
||||||
|
[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part
|
||||||
|
of your first [pull request][].
|
||||||
|
|
||||||
|
[AUTHORS]: AUTHORS
|
||||||
|
[CONTRIBUTORS]: CONTRIBUTORS
|
||||||
|
|
||||||
|
|
||||||
|
## Submitting a patch ##
|
||||||
|
|
||||||
|
1. It's generally best to start by opening a new issue describing the bug or
|
||||||
|
feature you're intending to fix. Even if you think it's relatively minor,
|
||||||
|
it's helpful to know what people are working on. Mention in the initial
|
||||||
|
issue that you are planning to work on that bug or feature so that it can
|
||||||
|
be assigned to you.
|
||||||
|
|
||||||
|
1. Follow the normal process of [forking][] the project, and setup a new
|
||||||
|
branch to work in. It's important that each group of changes be done in
|
||||||
|
separate branches in order to ensure that a pull request only includes the
|
||||||
|
commits related to that bug or feature.
|
||||||
|
|
||||||
|
1. Do your best to have [well-formed commit messages][] for each change.
|
||||||
|
This provides consistency throughout the project, and ensures that commit
|
||||||
|
messages are able to be formatted properly by various git tools.
|
||||||
|
|
||||||
|
1. Finally, push the commits to your fork and submit a [pull request][].
|
||||||
|
|
||||||
|
[forking]: https://help.github.com/articles/fork-a-repo
|
||||||
|
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||||
|
[pull request]: https://help.github.com/articles/creating-a-pull-request
|
||||||
@@ -26,13 +26,20 @@ Adam Eijdenberg <eijdenberg@google.com> <adam.eijdenberg@gmail.com>
|
|||||||
Al Cutter <al@google.com>
|
Al Cutter <al@google.com>
|
||||||
Ben Laurie <benl@google.com> <ben@links.org>
|
Ben Laurie <benl@google.com> <ben@links.org>
|
||||||
Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com>
|
Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com>
|
||||||
|
David Drysdale <drysdale@google.com>
|
||||||
Deyan Bektchiev <deyan.bektchiev@venafi.com> <deyan@bektchiev.net>
|
Deyan Bektchiev <deyan.bektchiev@venafi.com> <deyan@bektchiev.net>
|
||||||
Ed Maste <emaste@freebsd.org>
|
Ed Maste <emaste@freebsd.org>
|
||||||
Emilia Kasper <ekasper@google.com>
|
Emilia Kasper <ekasper@google.com>
|
||||||
Eran Messeri <eranm@google.com> <eran.mes@gmail.com>
|
Eran Messeri <eranm@google.com> <eran.mes@gmail.com>
|
||||||
|
Fiaz Hossain <fiaz.hossain@salesforce.com>
|
||||||
|
Gary Belvin <gbelvin@google.com> <gdbelvin@gmail.com>
|
||||||
Jeff Trawick <trawick@gmail.com>
|
Jeff Trawick <trawick@gmail.com>
|
||||||
|
Joe Tsai <joetsai@digital-static.net>
|
||||||
|
Kat Joyce <katjoyce@google.com>
|
||||||
Katriel Cohn-Gordon <katriel.cohn-gordon@cybersecurity.ox.ac.uk>
|
Katriel Cohn-Gordon <katriel.cohn-gordon@cybersecurity.ox.ac.uk>
|
||||||
|
Kiril Nikolov <kiril.nikolov@venafi.com>
|
||||||
Konrad Kraszewski <kraszewski@google.com> <laiquendir@gmail.com>
|
Konrad Kraszewski <kraszewski@google.com> <laiquendir@gmail.com>
|
||||||
|
Laël Cellier <lael.cellier@gmail.com>
|
||||||
Linus Nordberg <linus@nordu.net>
|
Linus Nordberg <linus@nordu.net>
|
||||||
Mark Schloesser <ms@mwcollect.org>
|
Mark Schloesser <ms@mwcollect.org>
|
||||||
Nicholas Galbreath <nickg@client9.com>
|
Nicholas Galbreath <nickg@client9.com>
|
||||||
@@ -41,7 +48,10 @@ Pascal Leroy <phl@google.com>
|
|||||||
Paul Hadfield <hadfieldp@google.com> <paul@phad.org.uk>
|
Paul Hadfield <hadfieldp@google.com> <paul@phad.org.uk>
|
||||||
Paul Lietar <lietar@google.com>
|
Paul Lietar <lietar@google.com>
|
||||||
Pierre Phaneuf <pphaneuf@google.com>
|
Pierre Phaneuf <pphaneuf@google.com>
|
||||||
|
Rob Percival <robpercival@google.com>
|
||||||
Rob Stradling <rob@comodo.com>
|
Rob Stradling <rob@comodo.com>
|
||||||
|
Roland Shoemaker <roland@letsencrypt.org>
|
||||||
Ruslan Kovalov <ruslan.kovalyov@gmail.com>
|
Ruslan Kovalov <ruslan.kovalyov@gmail.com>
|
||||||
|
Samuel Lidén Borell <samuel@kodafritt.se>
|
||||||
Vladimir Rutsky <vladimir@rutsky.org>
|
Vladimir Rutsky <vladimir@rutsky.org>
|
||||||
Ximin Luo <infinity0@gmx.com>
|
Ximin Luo <infinity0@gmx.com>
|
||||||
144
vendor/github.com/google/certificate-transparency-go/README.md
generated
vendored
Normal file
144
vendor/github.com/google/certificate-transparency-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Certificate Transparency: Go Code
|
||||||
|
|
||||||
|
[](https://travis-ci.org/google/certificate-transparency-go)
|
||||||
|
[](https://goreportcard.com/report/github.com/google/certificate-transparency-go)
|
||||||
|
[](https://godoc.org/github.com/google/certificate-transparency-go)
|
||||||
|
|
||||||
|
This repository holds Go code related to
|
||||||
|
[Certificate Transparency](https://www.certificate-transparency.org/) (CT). The
|
||||||
|
repository requires Go version 1.9.
|
||||||
|
|
||||||
|
- [Repository Structure](#repository-structure)
|
||||||
|
- [Trillian CT Personality](#trillian-ct-personality)
|
||||||
|
- [Working on the Code](#working-on-the-code)
|
||||||
|
- [Rebuilding Generated Code](#rebuilding-generated-code)
|
||||||
|
- [Updating Vendor Code](#updating-vendor-code)
|
||||||
|
- [Running Codebase Checks](#running-codebase-checks)
|
||||||
|
|
||||||
|
## Repository Structure
|
||||||
|
|
||||||
|
The main parts of the repository are:
|
||||||
|
|
||||||
|
- Encoding libraries:
|
||||||
|
- `asn1/` and `x509/` are forks of the upstream Go `encoding/asn1` and
|
||||||
|
`crypto/x509` libraries. We maintain separate forks of these packages
|
||||||
|
because CT is intended to act as an observatory of certificates across the
|
||||||
|
ecosystem; as such, we need to be able to process somewhat-malformed
|
||||||
|
certificates that the stricter upstream code would (correctly) reject.
|
||||||
|
Our `x509` fork also includes code for working with the
|
||||||
|
[pre-certificates defined in RFC 6962](https://tools.ietf.org/html/rfc6962#section-3.1).
|
||||||
|
- `tls` holds a library for processing TLS-encoded data as described in
|
||||||
|
[RFC 5246](https://tools.ietf.org/html/rfc5246).
|
||||||
|
- `x509util` provides additional utilities for dealing with
|
||||||
|
`x509.Certificate`s.
|
||||||
|
- CT client libraries:
|
||||||
|
- The top-level `ct` package (in `.`) holds types and utilities for working
|
||||||
|
with CT data structures defined in
|
||||||
|
[RFC 6962](https://tools.ietf.org/html/rfc6962).
|
||||||
|
- `client/` and `jsonclient/` hold libraries that allow access to CT Logs
|
||||||
|
via entrypoints described in
|
||||||
|
[section 4 of RFC 6962](https://tools.ietf.org/html/rfc6962#section-4).
|
||||||
|
- `scanner/` holds a library for scanning the entire contents of an existing
|
||||||
|
CT Log.
|
||||||
|
- Command line tools:
|
||||||
|
- `./client/ctclient` allows interaction with a CT Log
|
||||||
|
- `./scanner/scanlog` allows an existing CT Log to be scanned for certificates
|
||||||
|
of interest; please be polite when running this tool against a Log.
|
||||||
|
- `./x509util/certcheck` allows display and verification of certificates
|
||||||
|
- `./x509util/crlcheck` allows display and verification of certificate
|
||||||
|
revocation lists (CRLs).
|
||||||
|
- CT Personality for [Trillian](https://github.com/google/trillian):
|
||||||
|
- `trillian/` holds code that allows a Certificate Transparency Log to be
|
||||||
|
run using a Trillian Log as its back-end -- see
|
||||||
|
[below](#trillian-ct-personality).
|
||||||
|
|
||||||
|
|
||||||
|
## Trillian CT Personality
|
||||||
|
|
||||||
|
The `trillian/` subdirectory holds code and scripts for running a CT Log based
|
||||||
|
on the [Trillian](https://github.com/google/trillian) general transparency Log.
|
||||||
|
|
||||||
|
The main code for the CT personality is held in `trillian/ctfe`; this code
|
||||||
|
responds to HTTP requests on the
|
||||||
|
[CT API paths](https://tools.ietf.org/html/rfc6962#section-4) and translates
|
||||||
|
them to the equivalent gRPC API requests to the Trillian Log.
|
||||||
|
|
||||||
|
This obviously relies on the gRPC API definitions at
|
||||||
|
`github.com/google/trillian`; the code also uses common libraries from the
|
||||||
|
Trillian project for:
|
||||||
|
- exposing monitoring and statistics via an `interface` and corresponding
|
||||||
|
Prometheus implementation (`github.com/google/trillian/monitoring/...`)
|
||||||
|
- dealing with cryptographic keys (`github.com/google/trillian/crypto/...`).
|
||||||
|
|
||||||
|
The `trillian/integration/` directory holds scripts and tests for running the whole
|
||||||
|
system locally. In particular:
|
||||||
|
- `trillian/integration/ct_integration_test.sh` brings up local processes
|
||||||
|
running a Trillian Log server, signer and a CT personality, and exercises the
|
||||||
|
complete set of RFC 6962 API entrypoints.
|
||||||
|
- `trillian/integration/ct_hammer_test.sh` brings up a complete system and runs
|
||||||
|
a continuous randomized test of the CT entrypoints.
|
||||||
|
|
||||||
|
These scripts require a local database instance to be configured as described
|
||||||
|
in the [Trillian instructions](https://github.com/google/trillian#mysql-setup).
|
||||||
|
|
||||||
|
|
||||||
|
## Working on the Code
|
||||||
|
|
||||||
|
Developers who want to make changes to the codebase need some additional
|
||||||
|
dependencies and tools, described in the following sections. The
|
||||||
|
[Travis configuration](.travis.yml) for the codebase is also useful reference
|
||||||
|
for the required tools and scripts, as it may be more up-to-date than this
|
||||||
|
document.
|
||||||
|
|
||||||
|
### Rebuilding Generated Code
|
||||||
|
|
||||||
|
Some of the CT Go code is autogenerated from other files:
|
||||||
|
|
||||||
|
- [Protocol buffer](https://developers.google.com/protocol-buffers/) message
|
||||||
|
definitions are converted to `.pb.go` implementations.
|
||||||
|
- A mock implementation of the Trillian gRPC API (in `trillian/mockclient`) is
|
||||||
|
created with [GoMock](https://github.com/golang/mock).
|
||||||
|
|
||||||
|
Re-generating mock or protobuffer files is only needed if you're changing
|
||||||
|
the original files; if you do, you'll need to install the prerequisites:
|
||||||
|
|
||||||
|
- `mockgen` tool from https://github.com/golang/mock
|
||||||
|
- `protoc`, [Go support for protoc](https://github.com/golang/protobuf) (see
|
||||||
|
documentation linked from the
|
||||||
|
[protobuf site](https://github.com/google/protobuf))
|
||||||
|
|
||||||
|
and run the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go generate -x ./... # hunts for //go:generate comments and runs them
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating Vendor Code
|
||||||
|
|
||||||
|
The codebase includes a couple of external projects under the `vendor/`
|
||||||
|
subdirectory, to ensure that builds use a fixed version (typically because the
|
||||||
|
upstream repository does not guarantee back-compatibility between the tip
|
||||||
|
`master` branch and the current stable release). See
|
||||||
|
[instructions in the Trillian repo](https://github.com/google/trillian#updating-vendor-code)
|
||||||
|
for how to update vendored subtrees.
|
||||||
|
|
||||||
|
|
||||||
|
### Running Codebase Checks
|
||||||
|
|
||||||
|
The [`scripts/presubmit.sh`](scripts/presubmit.sh) script runs various tools
|
||||||
|
and tests over the codebase.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install gometalinter and all linters
|
||||||
|
go get -u github.com/alecthomas/gometalinter
|
||||||
|
gometalinter --install
|
||||||
|
|
||||||
|
# Run code generation, build, test and linters
|
||||||
|
./scripts/presubmit.sh
|
||||||
|
|
||||||
|
# Run build, test and linters but skip code generation
|
||||||
|
./scripts/presubmit.sh --no-generate
|
||||||
|
|
||||||
|
# Or just run the linters alone:
|
||||||
|
gometalinter --config=gometalinter.json ./...
|
||||||
|
```
|
||||||
@@ -7,7 +7,7 @@ go_library(
|
|||||||
"common.go",
|
"common.go",
|
||||||
"marshal.go",
|
"marshal.go",
|
||||||
],
|
],
|
||||||
importpath = "github.com/google/certificate-transparency/go/asn1",
|
importpath = "github.com/google/certificate-transparency-go/asn1",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
497
vendor/github.com/google/certificate-transparency/go/asn1/asn1.go → vendor/github.com/google/certificate-transparency-go/asn1/asn1.go
generated
vendored
Executable file → Normal file
497
vendor/github.com/google/certificate-transparency/go/asn1/asn1.go → vendor/github.com/google/certificate-transparency-go/asn1/asn1.go
generated
vendored
Executable file → Normal file
@@ -8,12 +8,10 @@
|
|||||||
// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
|
// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
|
||||||
// http://luca.ntop.org/Teaching/Appunti/asn1.html.
|
// http://luca.ntop.org/Teaching/Appunti/asn1.html.
|
||||||
//
|
//
|
||||||
// START CT CHANGES
|
|
||||||
// This is a fork of the Go standard library ASN.1 implementation
|
// This is a fork of the Go standard library ASN.1 implementation
|
||||||
// (encoding/asn1). The main difference is that this version tries to correct
|
// (encoding/asn1). The main difference is that this version tries to correct
|
||||||
// for errors (e.g. use of tagPrintableString when the string data is really
|
// for errors (e.g. use of tagPrintableString when the string data is really
|
||||||
// ISO8859-1 - a common error present in many x509 certificates in the wild.)
|
// ISO8859-1 - a common error present in many x509 certificates in the wild.)
|
||||||
// END CT CHANGES
|
|
||||||
package asn1
|
package asn1
|
||||||
|
|
||||||
// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
|
// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
|
||||||
@@ -27,40 +25,53 @@ package asn1
|
|||||||
// everything by any means.
|
// everything by any means.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// START CT CHANGES
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
// END CT CHANGES
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
// START CT CHANGES
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
// END CT CHANGES
|
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A StructuralError suggests that the ASN.1 data is valid, but the Go type
|
// A StructuralError suggests that the ASN.1 data is valid, but the Go type
|
||||||
// which is receiving it doesn't match.
|
// which is receiving it doesn't match.
|
||||||
type StructuralError struct {
|
type StructuralError struct {
|
||||||
Msg string
|
Msg string
|
||||||
|
Field string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e StructuralError) Error() string { return "asn1: structure error: " + e.Msg }
|
func (e StructuralError) Error() string {
|
||||||
|
var prefix string
|
||||||
|
if e.Field != "" {
|
||||||
|
prefix = e.Field + ": "
|
||||||
|
}
|
||||||
|
return "asn1: structure error: " + prefix + e.Msg
|
||||||
|
}
|
||||||
|
|
||||||
// A SyntaxError suggests that the ASN.1 data is invalid.
|
// A SyntaxError suggests that the ASN.1 data is invalid.
|
||||||
type SyntaxError struct {
|
type SyntaxError struct {
|
||||||
Msg string
|
Msg string
|
||||||
|
Field string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e SyntaxError) Error() string { return "asn1: syntax error: " + e.Msg }
|
func (e SyntaxError) Error() string {
|
||||||
|
var prefix string
|
||||||
|
if e.Field != "" {
|
||||||
|
prefix = e.Field + ": "
|
||||||
|
}
|
||||||
|
return "asn1: syntax error: " + prefix + e.Msg
|
||||||
|
}
|
||||||
|
|
||||||
// We start by dealing with each of the primitive types in turn.
|
// We start by dealing with each of the primitive types in turn.
|
||||||
|
|
||||||
// BOOLEAN
|
// BOOLEAN
|
||||||
|
|
||||||
func parseBool(bytes []byte) (ret bool, err error) {
|
func parseBool(bytes []byte, fieldName string) (ret bool, err error) {
|
||||||
if len(bytes) != 1 {
|
if len(bytes) != 1 {
|
||||||
err = SyntaxError{"invalid boolean"}
|
err = SyntaxError{"invalid boolean", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +84,7 @@ func parseBool(bytes []byte) (ret bool, err error) {
|
|||||||
case 0xff:
|
case 0xff:
|
||||||
ret = true
|
ret = true
|
||||||
default:
|
default:
|
||||||
err = SyntaxError{"invalid boolean"}
|
err = SyntaxError{"invalid boolean", fieldName}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -81,12 +92,31 @@ func parseBool(bytes []byte) (ret bool, err error) {
|
|||||||
|
|
||||||
// INTEGER
|
// INTEGER
|
||||||
|
|
||||||
|
// checkInteger returns nil if the given bytes are a valid DER-encoded
|
||||||
|
// INTEGER and an error otherwise.
|
||||||
|
func checkInteger(bytes []byte, fieldName string) error {
|
||||||
|
if len(bytes) == 0 {
|
||||||
|
return StructuralError{"empty integer", fieldName}
|
||||||
|
}
|
||||||
|
if len(bytes) == 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if (bytes[0] == 0 && bytes[1]&0x80 == 0) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) {
|
||||||
|
return StructuralError{"integer not minimally-encoded", fieldName}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseInt64 treats the given bytes as a big-endian, signed integer and
|
// parseInt64 treats the given bytes as a big-endian, signed integer and
|
||||||
// returns the result.
|
// returns the result.
|
||||||
func parseInt64(bytes []byte) (ret int64, err error) {
|
func parseInt64(bytes []byte, fieldName string) (ret int64, err error) {
|
||||||
|
err = checkInteger(bytes, fieldName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(bytes) > 8 {
|
if len(bytes) > 8 {
|
||||||
// We'll overflow an int64 in this case.
|
// We'll overflow an int64 in this case.
|
||||||
err = StructuralError{"integer too large"}
|
err = StructuralError{"integer too large", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
|
for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
|
||||||
@@ -102,13 +132,16 @@ func parseInt64(bytes []byte) (ret int64, err error) {
|
|||||||
|
|
||||||
// parseInt treats the given bytes as a big-endian, signed integer and returns
|
// parseInt treats the given bytes as a big-endian, signed integer and returns
|
||||||
// the result.
|
// the result.
|
||||||
func parseInt32(bytes []byte) (int32, error) {
|
func parseInt32(bytes []byte, fieldName string) (int32, error) {
|
||||||
ret64, err := parseInt64(bytes)
|
if err := checkInteger(bytes, fieldName); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
ret64, err := parseInt64(bytes, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if ret64 != int64(int32(ret64)) {
|
if ret64 != int64(int32(ret64)) {
|
||||||
return 0, StructuralError{"integer too large"}
|
return 0, StructuralError{"integer too large", fieldName}
|
||||||
}
|
}
|
||||||
return int32(ret64), nil
|
return int32(ret64), nil
|
||||||
}
|
}
|
||||||
@@ -117,7 +150,10 @@ var bigOne = big.NewInt(1)
|
|||||||
|
|
||||||
// parseBigInt treats the given bytes as a big-endian, signed integer and returns
|
// parseBigInt treats the given bytes as a big-endian, signed integer and returns
|
||||||
// the result.
|
// the result.
|
||||||
func parseBigInt(bytes []byte) *big.Int {
|
func parseBigInt(bytes []byte, fieldName string) (*big.Int, error) {
|
||||||
|
if err := checkInteger(bytes, fieldName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
ret := new(big.Int)
|
ret := new(big.Int)
|
||||||
if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
|
if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
|
||||||
// This is a negative number.
|
// This is a negative number.
|
||||||
@@ -128,10 +164,10 @@ func parseBigInt(bytes []byte) *big.Int {
|
|||||||
ret.SetBytes(notBytes)
|
ret.SetBytes(notBytes)
|
||||||
ret.Add(ret, bigOne)
|
ret.Add(ret, bigOne)
|
||||||
ret.Neg(ret)
|
ret.Neg(ret)
|
||||||
return ret
|
return ret, nil
|
||||||
}
|
}
|
||||||
ret.SetBytes(bytes)
|
ret.SetBytes(bytes)
|
||||||
return ret
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BIT STRING
|
// BIT STRING
|
||||||
@@ -174,16 +210,16 @@ func (b BitString) RightAlign() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
|
// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
|
||||||
func parseBitString(bytes []byte) (ret BitString, err error) {
|
func parseBitString(bytes []byte, fieldName string) (ret BitString, err error) {
|
||||||
if len(bytes) == 0 {
|
if len(bytes) == 0 {
|
||||||
err = SyntaxError{"zero length BIT STRING"}
|
err = SyntaxError{"zero length BIT STRING", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
paddingBits := int(bytes[0])
|
paddingBits := int(bytes[0])
|
||||||
if paddingBits > 7 ||
|
if paddingBits > 7 ||
|
||||||
len(bytes) == 1 && paddingBits > 0 ||
|
len(bytes) == 1 && paddingBits > 0 ||
|
||||||
bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
|
bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
|
||||||
err = SyntaxError{"invalid padding bits in BIT STRING"}
|
err = SyntaxError{"invalid padding bits in BIT STRING", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret.BitLength = (len(bytes)-1)*8 - paddingBits
|
ret.BitLength = (len(bytes)-1)*8 - paddingBits
|
||||||
@@ -191,6 +227,14 @@ func parseBitString(bytes []byte) (ret BitString, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NULL
|
||||||
|
|
||||||
|
// NullRawValue is a RawValue with its Tag set to the ASN.1 NULL type tag (5).
|
||||||
|
var NullRawValue = RawValue{Tag: TagNull}
|
||||||
|
|
||||||
|
// NullBytes contains bytes representing the DER-encoded ASN.1 NULL type.
|
||||||
|
var NullBytes = []byte{TagNull, 0}
|
||||||
|
|
||||||
// OBJECT IDENTIFIER
|
// OBJECT IDENTIFIER
|
||||||
|
|
||||||
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
|
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
|
||||||
@@ -210,12 +254,25 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (oi ObjectIdentifier) String() string {
|
||||||
|
var s string
|
||||||
|
|
||||||
|
for i, v := range oi {
|
||||||
|
if i > 0 {
|
||||||
|
s += "."
|
||||||
|
}
|
||||||
|
s += strconv.Itoa(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
|
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
|
||||||
// returns it. An object identifier is a sequence of variable length integers
|
// returns it. An object identifier is a sequence of variable length integers
|
||||||
// that are assigned in a hierarchy.
|
// that are assigned in a hierarchy.
|
||||||
func parseObjectIdentifier(bytes []byte) (s []int, err error) {
|
func parseObjectIdentifier(bytes []byte, fieldName string) (s []int, err error) {
|
||||||
if len(bytes) == 0 {
|
if len(bytes) == 0 {
|
||||||
err = SyntaxError{"zero length OBJECT IDENTIFIER"}
|
err = SyntaxError{"zero length OBJECT IDENTIFIER", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +284,7 @@ func parseObjectIdentifier(bytes []byte) (s []int, err error) {
|
|||||||
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||||
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||||
// then there are no restrictions on value2.
|
// then there are no restrictions on value2.
|
||||||
v, offset, err := parseBase128Int(bytes, 0)
|
v, offset, err := parseBase128Int(bytes, 0, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -241,7 +298,7 @@ func parseObjectIdentifier(bytes []byte) (s []int, err error) {
|
|||||||
|
|
||||||
i := 2
|
i := 2
|
||||||
for ; offset < len(bytes); i++ {
|
for ; offset < len(bytes); i++ {
|
||||||
v, offset, err = parseBase128Int(bytes, offset)
|
v, offset, err = parseBase128Int(bytes, offset, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -263,22 +320,30 @@ type Flag bool
|
|||||||
|
|
||||||
// parseBase128Int parses a base-128 encoded int from the given offset in the
|
// parseBase128Int parses a base-128 encoded int from the given offset in the
|
||||||
// given byte slice. It returns the value and the new offset.
|
// given byte slice. It returns the value and the new offset.
|
||||||
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
|
func parseBase128Int(bytes []byte, initOffset int, fieldName string) (ret, offset int, err error) {
|
||||||
offset = initOffset
|
offset = initOffset
|
||||||
|
var ret64 int64
|
||||||
for shifted := 0; offset < len(bytes); shifted++ {
|
for shifted := 0; offset < len(bytes); shifted++ {
|
||||||
if shifted > 4 {
|
// 5 * 7 bits per byte == 35 bits of data
|
||||||
err = StructuralError{"base 128 integer too large"}
|
// Thus the representation is either non-minimal or too large for an int32
|
||||||
|
if shifted == 5 {
|
||||||
|
err = StructuralError{"base 128 integer too large", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret <<= 7
|
ret64 <<= 7
|
||||||
b := bytes[offset]
|
b := bytes[offset]
|
||||||
ret |= int(b & 0x7f)
|
ret64 |= int64(b & 0x7f)
|
||||||
offset++
|
offset++
|
||||||
if b&0x80 == 0 {
|
if b&0x80 == 0 {
|
||||||
|
ret = int(ret64)
|
||||||
|
// Ensure that the returned value fits in an int on all platforms
|
||||||
|
if ret64 > math.MaxInt32 {
|
||||||
|
err = StructuralError{"base 128 integer too large", fieldName}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = SyntaxError{"truncated base 128 integer"}
|
err = SyntaxError{"truncated base 128 integer", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,11 +351,23 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
|
|||||||
|
|
||||||
func parseUTCTime(bytes []byte) (ret time.Time, err error) {
|
func parseUTCTime(bytes []byte) (ret time.Time, err error) {
|
||||||
s := string(bytes)
|
s := string(bytes)
|
||||||
ret, err = time.Parse("0601021504Z0700", s)
|
|
||||||
|
formatStr := "0601021504Z0700"
|
||||||
|
ret, err = time.Parse(formatStr, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ret, err = time.Parse("060102150405Z0700", s)
|
formatStr = "060102150405Z0700"
|
||||||
|
ret, err = time.Parse(formatStr, s)
|
||||||
}
|
}
|
||||||
if err == nil && ret.Year() >= 2050 {
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if serialized := ret.Format(formatStr); serialized != s {
|
||||||
|
err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.Year() >= 2050 {
|
||||||
// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
|
// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
|
||||||
ret = ret.AddDate(-100, 0, 0)
|
ret = ret.AddDate(-100, 0, 0)
|
||||||
}
|
}
|
||||||
@@ -301,17 +378,47 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) {
|
|||||||
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
|
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
|
||||||
// and returns the resulting time.
|
// and returns the resulting time.
|
||||||
func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
|
func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
|
||||||
return time.Parse("20060102150405Z0700", string(bytes))
|
const formatStr = "20060102150405Z0700"
|
||||||
|
s := string(bytes)
|
||||||
|
|
||||||
|
if ret, err = time.Parse(formatStr, s); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if serialized := ret.Format(formatStr); serialized != s {
|
||||||
|
err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumericString
|
||||||
|
|
||||||
|
// parseNumericString parses an ASN.1 NumericString from the given byte array
|
||||||
|
// and returns it.
|
||||||
|
func parseNumericString(bytes []byte, fieldName string) (ret string, err error) {
|
||||||
|
for _, b := range bytes {
|
||||||
|
if !isNumeric(b) {
|
||||||
|
return "", SyntaxError{"NumericString contains invalid character", fieldName}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isNumeric reports whether the given b is in the ASN.1 NumericString set.
|
||||||
|
func isNumeric(b byte) bool {
|
||||||
|
return '0' <= b && b <= '9' ||
|
||||||
|
b == ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintableString
|
// PrintableString
|
||||||
|
|
||||||
// parsePrintableString parses a ASN.1 PrintableString from the given byte
|
// parsePrintableString parses an ASN.1 PrintableString from the given byte
|
||||||
// array and returns it.
|
// array and returns it.
|
||||||
func parsePrintableString(bytes []byte) (ret string, err error) {
|
func parsePrintableString(bytes []byte, fieldName string) (ret string, err error) {
|
||||||
for _, b := range bytes {
|
for _, b := range bytes {
|
||||||
if !isPrintable(b) {
|
if !isPrintable(b, allowAsterisk, allowAmpersand) {
|
||||||
err = SyntaxError{"PrintableString contains invalid character"}
|
err = SyntaxError{"PrintableString contains invalid character", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,8 +426,21 @@ func parsePrintableString(bytes []byte) (ret string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
|
type asteriskFlag bool
|
||||||
func isPrintable(b byte) bool {
|
type ampersandFlag bool
|
||||||
|
|
||||||
|
const (
|
||||||
|
allowAsterisk asteriskFlag = true
|
||||||
|
rejectAsterisk asteriskFlag = false
|
||||||
|
|
||||||
|
allowAmpersand ampersandFlag = true
|
||||||
|
rejectAmpersand ampersandFlag = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// isPrintable reports whether the given b is in the ASN.1 PrintableString set.
|
||||||
|
// If asterisk is allowAsterisk then '*' is also allowed, reflecting existing
|
||||||
|
// practice. If ampersand is allowAmpersand then '&' is allowed as well.
|
||||||
|
func isPrintable(b byte, asterisk asteriskFlag, ampersand ampersandFlag) bool {
|
||||||
return 'a' <= b && b <= 'z' ||
|
return 'a' <= b && b <= 'z' ||
|
||||||
'A' <= b && b <= 'Z' ||
|
'A' <= b && b <= 'Z' ||
|
||||||
'0' <= b && b <= '9' ||
|
'0' <= b && b <= '9' ||
|
||||||
@@ -333,17 +453,22 @@ func isPrintable(b byte) bool {
|
|||||||
// This is technically not allowed in a PrintableString.
|
// This is technically not allowed in a PrintableString.
|
||||||
// However, x509 certificates with wildcard strings don't
|
// However, x509 certificates with wildcard strings don't
|
||||||
// always use the correct string type so we permit it.
|
// always use the correct string type so we permit it.
|
||||||
b == '*'
|
(bool(asterisk) && b == '*') ||
|
||||||
|
// This is not technically allowed either. However, not
|
||||||
|
// only is it relatively common, but there are also a
|
||||||
|
// handful of CA certificates that contain it. At least
|
||||||
|
// one of which will not expire until 2027.
|
||||||
|
(bool(ampersand) && b == '&')
|
||||||
}
|
}
|
||||||
|
|
||||||
// IA5String
|
// IA5String
|
||||||
|
|
||||||
// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
|
// parseIA5String parses an ASN.1 IA5String (ASCII string) from the given
|
||||||
// byte slice and returns it.
|
// byte slice and returns it.
|
||||||
func parseIA5String(bytes []byte) (ret string, err error) {
|
func parseIA5String(bytes []byte, fieldName string) (ret string, err error) {
|
||||||
for _, b := range bytes {
|
for _, b := range bytes {
|
||||||
if b >= 0x80 {
|
if b >= utf8.RuneSelf {
|
||||||
err = SyntaxError{"IA5String contains invalid character"}
|
err = SyntaxError{"IA5String contains invalid character", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,7 +478,7 @@ func parseIA5String(bytes []byte) (ret string, err error) {
|
|||||||
|
|
||||||
// T61String
|
// T61String
|
||||||
|
|
||||||
// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
|
// parseT61String parses an ASN.1 T61String (8-bit clean string) from the given
|
||||||
// byte slice and returns it.
|
// byte slice and returns it.
|
||||||
func parseT61String(bytes []byte) (ret string, err error) {
|
func parseT61String(bytes []byte) (ret string, err error) {
|
||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
@@ -361,9 +486,12 @@ func parseT61String(bytes []byte) (ret string, err error) {
|
|||||||
|
|
||||||
// UTF8String
|
// UTF8String
|
||||||
|
|
||||||
// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
|
// parseUTF8String parses an ASN.1 UTF8String (raw UTF-8) from the given byte
|
||||||
// array and returns it.
|
// array and returns it.
|
||||||
func parseUTF8String(bytes []byte) (ret string, err error) {
|
func parseUTF8String(bytes []byte) (ret string, err error) {
|
||||||
|
if !utf8.Valid(bytes) {
|
||||||
|
return "", errors.New("asn1: invalid UTF-8 string")
|
||||||
|
}
|
||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,8 +514,14 @@ type RawContent []byte
|
|||||||
// into a byte slice. It returns the parsed data and the new offset. SET and
|
// into a byte slice. It returns the parsed data and the new offset. SET and
|
||||||
// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
|
// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
|
||||||
// don't distinguish between ordered and unordered objects in this code.
|
// don't distinguish between ordered and unordered objects in this code.
|
||||||
func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) {
|
func parseTagAndLength(bytes []byte, initOffset int, fieldName string) (ret tagAndLength, offset int, err error) {
|
||||||
offset = initOffset
|
offset = initOffset
|
||||||
|
// parseTagAndLength should not be called without at least a single
|
||||||
|
// byte to read. Thus this check is for robustness:
|
||||||
|
if offset >= len(bytes) {
|
||||||
|
err = errors.New("asn1: internal error in parseTagAndLength")
|
||||||
|
return
|
||||||
|
}
|
||||||
b := bytes[offset]
|
b := bytes[offset]
|
||||||
offset++
|
offset++
|
||||||
ret.class = int(b >> 6)
|
ret.class = int(b >> 6)
|
||||||
@@ -397,13 +531,18 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
|
|||||||
// If the bottom five bits are set, then the tag number is actually base 128
|
// If the bottom five bits are set, then the tag number is actually base 128
|
||||||
// encoded afterwards
|
// encoded afterwards
|
||||||
if ret.tag == 0x1f {
|
if ret.tag == 0x1f {
|
||||||
ret.tag, offset, err = parseBase128Int(bytes, offset)
|
ret.tag, offset, err = parseBase128Int(bytes, offset, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Tags should be encoded in minimal form.
|
||||||
|
if ret.tag < 0x1f {
|
||||||
|
err = SyntaxError{"non-minimal tag", fieldName}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if offset >= len(bytes) {
|
if offset >= len(bytes) {
|
||||||
err = SyntaxError{"truncated tag or length"}
|
err = SyntaxError{"truncated tag or length", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b = bytes[offset]
|
b = bytes[offset]
|
||||||
@@ -415,13 +554,13 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
|
|||||||
// Bottom 7 bits give the number of length bytes to follow.
|
// Bottom 7 bits give the number of length bytes to follow.
|
||||||
numBytes := int(b & 0x7f)
|
numBytes := int(b & 0x7f)
|
||||||
if numBytes == 0 {
|
if numBytes == 0 {
|
||||||
err = SyntaxError{"indefinite length found (not DER)"}
|
err = SyntaxError{"indefinite length found (not DER)", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret.length = 0
|
ret.length = 0
|
||||||
for i := 0; i < numBytes; i++ {
|
for i := 0; i < numBytes; i++ {
|
||||||
if offset >= len(bytes) {
|
if offset >= len(bytes) {
|
||||||
err = SyntaxError{"truncated tag or length"}
|
err = SyntaxError{"truncated tag or length", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b = bytes[offset]
|
b = bytes[offset]
|
||||||
@@ -429,17 +568,22 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
|
|||||||
if ret.length >= 1<<23 {
|
if ret.length >= 1<<23 {
|
||||||
// We can't shift ret.length up without
|
// We can't shift ret.length up without
|
||||||
// overflowing.
|
// overflowing.
|
||||||
err = StructuralError{"length too large"}
|
err = StructuralError{"length too large", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret.length <<= 8
|
ret.length <<= 8
|
||||||
ret.length |= int(b)
|
ret.length |= int(b)
|
||||||
if ret.length == 0 {
|
if ret.length == 0 {
|
||||||
// DER requires that lengths be minimal.
|
// DER requires that lengths be minimal.
|
||||||
err = StructuralError{"superfluous leading zeros in length"}
|
err = StructuralError{"superfluous leading zeros in length", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Short lengths must be encoded in short form.
|
||||||
|
if ret.length < 0x80 {
|
||||||
|
err = StructuralError{"non-minimal length", fieldName}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -448,10 +592,10 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
|
|||||||
// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
|
// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
|
||||||
// a number of ASN.1 values from the given byte slice and returns them as a
|
// a number of ASN.1 values from the given byte slice and returns them as a
|
||||||
// slice of Go values of the given type.
|
// slice of Go values of the given type.
|
||||||
func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err error) {
|
func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type, fieldName string) (ret reflect.Value, err error) {
|
||||||
expectedTag, compoundType, ok := getUniversalType(elemType)
|
matchAny, expectedTag, compoundType, ok := getUniversalType(elemType)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = StructuralError{"unknown Go type for slice"}
|
err = StructuralError{"unknown Go type for slice", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,21 +604,27 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
|
|||||||
numElements := 0
|
numElements := 0
|
||||||
for offset := 0; offset < len(bytes); {
|
for offset := 0; offset < len(bytes); {
|
||||||
var t tagAndLength
|
var t tagAndLength
|
||||||
t, offset, err = parseTagAndLength(bytes, offset)
|
t, offset, err = parseTagAndLength(bytes, offset, fieldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
|
switch t.tag {
|
||||||
// that a sequence of them can be parsed into a []string.
|
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString:
|
||||||
if t.tag == tagGeneralString {
|
// We pretend that various other string types are
|
||||||
t.tag = tagPrintableString
|
// PRINTABLE STRINGs so that a sequence of them can be
|
||||||
|
// parsed into a []string.
|
||||||
|
t.tag = TagPrintableString
|
||||||
|
case TagGeneralizedTime, TagUTCTime:
|
||||||
|
// Likewise, both time types are treated the same.
|
||||||
|
t.tag = TagUTCTime
|
||||||
}
|
}
|
||||||
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
|
|
||||||
err = StructuralError{"sequence tag mismatch"}
|
if !matchAny && (t.class != ClassUniversal || t.isCompound != compoundType || t.tag != expectedTag) {
|
||||||
|
err = StructuralError{fmt.Sprintf("sequence tag mismatch (got:%+v, want:0/%d/%t)", t, expectedTag, compoundType), fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if invalidLength(offset, t.length, len(bytes)) {
|
if invalidLength(offset, t.length, len(bytes)) {
|
||||||
err = SyntaxError{"truncated sequence"}
|
err = SyntaxError{"truncated sequence", fieldName}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
offset += t.length
|
offset += t.length
|
||||||
@@ -509,8 +659,6 @@ func invalidLength(offset, length, sliceLength int) bool {
|
|||||||
return offset+length < offset || offset+length > sliceLength
|
return offset+length < offset || offset+length > sliceLength
|
||||||
}
|
}
|
||||||
|
|
||||||
// START CT CHANGES
|
|
||||||
|
|
||||||
// Tests whether the data in |bytes| would be a valid ISO8859-1 string.
|
// Tests whether the data in |bytes| would be a valid ISO8859-1 string.
|
||||||
// Clearly, a sequence of bytes comprised solely of valid ISO8859-1
|
// Clearly, a sequence of bytes comprised solely of valid ISO8859-1
|
||||||
// codepoints does not imply that the encoding MUST be ISO8859-1, rather that
|
// codepoints does not imply that the encoding MUST be ISO8859-1, rather that
|
||||||
@@ -556,8 +704,6 @@ func iso8859_1ToUTF8(bytes []byte) string {
|
|||||||
return string(buf)
|
return string(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// END CT CHANGES
|
|
||||||
|
|
||||||
// parseField is the main parsing function. Given a byte slice and an offset
|
// parseField is the main parsing function. Given a byte slice and an offset
|
||||||
// into the array, it will try to parse a suitable ASN.1 value out and store it
|
// into the array, it will try to parse a suitable ASN.1 value out and store it
|
||||||
// in the given Value.
|
// in the given Value.
|
||||||
@@ -568,46 +714,28 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
// If we have run out of data, it may be that there are optional elements at the end.
|
// If we have run out of data, it may be that there are optional elements at the end.
|
||||||
if offset == len(bytes) {
|
if offset == len(bytes) {
|
||||||
if !setDefaultValue(v, params) {
|
if !setDefaultValue(v, params) {
|
||||||
err = SyntaxError{"sequence truncated"}
|
err = SyntaxError{"sequence truncated", params.name}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deal with raw values.
|
|
||||||
if fieldType == rawValueType {
|
|
||||||
var t tagAndLength
|
|
||||||
t, offset, err = parseTagAndLength(bytes, offset)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if invalidLength(offset, t.length, len(bytes)) {
|
|
||||||
err = SyntaxError{"data truncated"}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
|
|
||||||
offset += t.length
|
|
||||||
v.Set(reflect.ValueOf(result))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deal with the ANY type.
|
// Deal with the ANY type.
|
||||||
if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
|
if ifaceType := fieldType; ifaceType.Kind() == reflect.Interface && ifaceType.NumMethod() == 0 {
|
||||||
var t tagAndLength
|
var t tagAndLength
|
||||||
t, offset, err = parseTagAndLength(bytes, offset)
|
t, offset, err = parseTagAndLength(bytes, offset, params.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if invalidLength(offset, t.length, len(bytes)) {
|
if invalidLength(offset, t.length, len(bytes)) {
|
||||||
err = SyntaxError{"data truncated"}
|
err = SyntaxError{"data truncated", params.name}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var result interface{}
|
var result interface{}
|
||||||
if !t.isCompound && t.class == classUniversal {
|
if !t.isCompound && t.class == ClassUniversal {
|
||||||
innerBytes := bytes[offset : offset+t.length]
|
innerBytes := bytes[offset : offset+t.length]
|
||||||
switch t.tag {
|
switch t.tag {
|
||||||
case tagPrintableString:
|
case TagPrintableString:
|
||||||
result, err = parsePrintableString(innerBytes)
|
result, err = parsePrintableString(innerBytes, params.name)
|
||||||
// START CT CHANGES
|
|
||||||
if err != nil && strings.Contains(err.Error(), "PrintableString contains invalid character") {
|
if err != nil && strings.Contains(err.Error(), "PrintableString contains invalid character") {
|
||||||
// Probably an ISO8859-1 string stuffed in, check if it
|
// Probably an ISO8859-1 string stuffed in, check if it
|
||||||
// would be valid and assume that's what's happened if so,
|
// would be valid and assume that's what's happened if so,
|
||||||
@@ -623,22 +751,25 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
err = errors.New("PrintableString contains invalid character, but couldn't determine correct String type.")
|
err = errors.New("PrintableString contains invalid character, but couldn't determine correct String type.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// END CT CHANGES
|
case TagNumericString:
|
||||||
case tagIA5String:
|
result, err = parseNumericString(innerBytes, params.name)
|
||||||
result, err = parseIA5String(innerBytes)
|
case TagIA5String:
|
||||||
case tagT61String:
|
result, err = parseIA5String(innerBytes, params.name)
|
||||||
|
case TagT61String:
|
||||||
result, err = parseT61String(innerBytes)
|
result, err = parseT61String(innerBytes)
|
||||||
case tagUTF8String:
|
case TagUTF8String:
|
||||||
result, err = parseUTF8String(innerBytes)
|
result, err = parseUTF8String(innerBytes)
|
||||||
case tagInteger:
|
case TagInteger:
|
||||||
result, err = parseInt64(innerBytes)
|
result, err = parseInt64(innerBytes, params.name)
|
||||||
case tagBitString:
|
case TagBitString:
|
||||||
result, err = parseBitString(innerBytes)
|
result, err = parseBitString(innerBytes, params.name)
|
||||||
case tagOID:
|
case TagOID:
|
||||||
result, err = parseObjectIdentifier(innerBytes)
|
result, err = parseObjectIdentifier(innerBytes, params.name)
|
||||||
case tagUTCTime:
|
case TagUTCTime:
|
||||||
result, err = parseUTCTime(innerBytes)
|
result, err = parseUTCTime(innerBytes)
|
||||||
case tagOctetString:
|
case TagGeneralizedTime:
|
||||||
|
result, err = parseGeneralizedTime(innerBytes)
|
||||||
|
case TagOctetString:
|
||||||
result = innerBytes
|
result = innerBytes
|
||||||
default:
|
default:
|
||||||
// If we don't know how to handle the type, we just leave Value as nil.
|
// If we don't know how to handle the type, we just leave Value as nil.
|
||||||
@@ -653,30 +784,31 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
universalTag, compoundType, ok1 := getUniversalType(fieldType)
|
|
||||||
if !ok1 {
|
|
||||||
err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, offset, err := parseTagAndLength(bytes, offset)
|
t, offset, err := parseTagAndLength(bytes, offset, params.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if params.explicit {
|
if params.explicit {
|
||||||
expectedClass := classContextSpecific
|
expectedClass := ClassContextSpecific
|
||||||
if params.application {
|
if params.application {
|
||||||
expectedClass = classApplication
|
expectedClass = ClassApplication
|
||||||
|
}
|
||||||
|
if offset == len(bytes) {
|
||||||
|
err = StructuralError{"explicit tag has no child", params.name}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
|
if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
|
||||||
if t.length > 0 {
|
if fieldType == rawValueType {
|
||||||
t, offset, err = parseTagAndLength(bytes, offset)
|
// The inner element should not be parsed for RawValues.
|
||||||
|
} else if t.length > 0 {
|
||||||
|
t, offset, err = parseTagAndLength(bytes, offset, params.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if fieldType != flagType {
|
if fieldType != flagType {
|
||||||
err = StructuralError{"zero length explicit tag was not an asn1.Flag"}
|
err = StructuralError{"zero length explicit tag was not an asn1.Flag", params.name}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v.SetBool(true)
|
v.SetBool(true)
|
||||||
@@ -688,55 +820,73 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
if ok {
|
if ok {
|
||||||
offset = initOffset
|
offset = initOffset
|
||||||
} else {
|
} else {
|
||||||
err = StructuralError{"explicitly tagged member didn't match"}
|
err = StructuralError{"explicitly tagged member didn't match", params.name}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchAny, universalTag, compoundType, ok1 := getUniversalType(fieldType)
|
||||||
|
if !ok1 {
|
||||||
|
err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType), params.name}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Special case for strings: all the ASN.1 string types map to the Go
|
// Special case for strings: all the ASN.1 string types map to the Go
|
||||||
// type string. getUniversalType returns the tag for PrintableString
|
// type string. getUniversalType returns the tag for PrintableString
|
||||||
// when it sees a string, so if we see a different string type on the
|
// when it sees a string, so if we see a different string type on the
|
||||||
// wire, we change the universal type to match.
|
// wire, we change the universal type to match.
|
||||||
if universalTag == tagPrintableString {
|
if universalTag == TagPrintableString {
|
||||||
|
if t.class == ClassUniversal {
|
||||||
switch t.tag {
|
switch t.tag {
|
||||||
case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
|
case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString:
|
||||||
universalTag = t.tag
|
universalTag = t.tag
|
||||||
}
|
}
|
||||||
|
} else if params.stringType != 0 {
|
||||||
|
universalTag = params.stringType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for time: UTCTime and GeneralizedTime both map to the
|
// Special case for time: UTCTime and GeneralizedTime both map to the
|
||||||
// Go type time.Time.
|
// Go type time.Time.
|
||||||
if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
|
if universalTag == TagUTCTime && t.tag == TagGeneralizedTime && t.class == ClassUniversal {
|
||||||
universalTag = tagGeneralizedTime
|
universalTag = TagGeneralizedTime
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedClass := classUniversal
|
if params.set {
|
||||||
|
universalTag = TagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
matchAnyClassAndTag := matchAny
|
||||||
|
expectedClass := ClassUniversal
|
||||||
expectedTag := universalTag
|
expectedTag := universalTag
|
||||||
|
|
||||||
if !params.explicit && params.tag != nil {
|
if !params.explicit && params.tag != nil {
|
||||||
expectedClass = classContextSpecific
|
expectedClass = ClassContextSpecific
|
||||||
expectedTag = *params.tag
|
expectedTag = *params.tag
|
||||||
|
matchAnyClassAndTag = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !params.explicit && params.application && params.tag != nil {
|
if !params.explicit && params.application && params.tag != nil {
|
||||||
expectedClass = classApplication
|
expectedClass = ClassApplication
|
||||||
expectedTag = *params.tag
|
expectedTag = *params.tag
|
||||||
|
matchAnyClassAndTag = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have unwrapped any explicit tagging at this point.
|
// We have unwrapped any explicit tagging at this point.
|
||||||
if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
|
if !matchAnyClassAndTag && (t.class != expectedClass || t.tag != expectedTag) ||
|
||||||
|
(!matchAny && t.isCompound != compoundType) {
|
||||||
// Tags don't match. Again, it could be an optional element.
|
// Tags don't match. Again, it could be an optional element.
|
||||||
ok := setDefaultValue(v, params)
|
ok := setDefaultValue(v, params)
|
||||||
if ok {
|
if ok {
|
||||||
offset = initOffset
|
offset = initOffset
|
||||||
} else {
|
} else {
|
||||||
err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
|
err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset), params.name}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if invalidLength(offset, t.length, len(bytes)) {
|
if invalidLength(offset, t.length, len(bytes)) {
|
||||||
err = SyntaxError{"data truncated"}
|
err = SyntaxError{"data truncated", params.name}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
innerBytes := bytes[offset : offset+t.length]
|
innerBytes := bytes[offset : offset+t.length]
|
||||||
@@ -744,8 +894,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
|
|
||||||
// We deal with the structures defined in this package first.
|
// We deal with the structures defined in this package first.
|
||||||
switch fieldType {
|
switch fieldType {
|
||||||
|
case rawValueType:
|
||||||
|
result := RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]}
|
||||||
|
v.Set(reflect.ValueOf(result))
|
||||||
|
return
|
||||||
case objectIdentifierType:
|
case objectIdentifierType:
|
||||||
newSlice, err1 := parseObjectIdentifier(innerBytes)
|
newSlice, err1 := parseObjectIdentifier(innerBytes, params.name)
|
||||||
v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
|
v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
reflect.Copy(v, reflect.ValueOf(newSlice))
|
reflect.Copy(v, reflect.ValueOf(newSlice))
|
||||||
@@ -753,7 +907,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
err = err1
|
err = err1
|
||||||
return
|
return
|
||||||
case bitStringType:
|
case bitStringType:
|
||||||
bs, err1 := parseBitString(innerBytes)
|
bs, err1 := parseBitString(innerBytes, params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
v.Set(reflect.ValueOf(bs))
|
v.Set(reflect.ValueOf(bs))
|
||||||
}
|
}
|
||||||
@@ -762,7 +916,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
case timeType:
|
case timeType:
|
||||||
var time time.Time
|
var time time.Time
|
||||||
var err1 error
|
var err1 error
|
||||||
if universalTag == tagUTCTime {
|
if universalTag == TagUTCTime {
|
||||||
time, err1 = parseUTCTime(innerBytes)
|
time, err1 = parseUTCTime(innerBytes)
|
||||||
} else {
|
} else {
|
||||||
time, err1 = parseGeneralizedTime(innerBytes)
|
time, err1 = parseGeneralizedTime(innerBytes)
|
||||||
@@ -773,7 +927,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
err = err1
|
err = err1
|
||||||
return
|
return
|
||||||
case enumeratedType:
|
case enumeratedType:
|
||||||
parsedInt, err1 := parseInt32(innerBytes)
|
parsedInt, err1 := parseInt32(innerBytes, params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
v.SetInt(int64(parsedInt))
|
v.SetInt(int64(parsedInt))
|
||||||
}
|
}
|
||||||
@@ -783,13 +937,16 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
v.SetBool(true)
|
v.SetBool(true)
|
||||||
return
|
return
|
||||||
case bigIntType:
|
case bigIntType:
|
||||||
parsedInt := parseBigInt(innerBytes)
|
parsedInt, err1 := parseBigInt(innerBytes, params.name)
|
||||||
|
if err1 == nil {
|
||||||
v.Set(reflect.ValueOf(parsedInt))
|
v.Set(reflect.ValueOf(parsedInt))
|
||||||
|
}
|
||||||
|
err = err1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch val := v; val.Kind() {
|
switch val := v; val.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
parsedBool, err1 := parseBool(innerBytes)
|
parsedBool, err1 := parseBool(innerBytes, params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
val.SetBool(parsedBool)
|
val.SetBool(parsedBool)
|
||||||
}
|
}
|
||||||
@@ -797,13 +954,13 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
return
|
return
|
||||||
case reflect.Int, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
if val.Type().Size() == 4 {
|
if val.Type().Size() == 4 {
|
||||||
parsedInt, err1 := parseInt32(innerBytes)
|
parsedInt, err1 := parseInt32(innerBytes, params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
val.SetInt(int64(parsedInt))
|
val.SetInt(int64(parsedInt))
|
||||||
}
|
}
|
||||||
err = err1
|
err = err1
|
||||||
} else {
|
} else {
|
||||||
parsedInt, err1 := parseInt64(innerBytes)
|
parsedInt, err1 := parseInt64(innerBytes, params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
val.SetInt(parsedInt)
|
val.SetInt(parsedInt)
|
||||||
}
|
}
|
||||||
@@ -814,6 +971,13 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
structType := fieldType
|
structType := fieldType
|
||||||
|
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
if structType.Field(i).PkgPath != "" {
|
||||||
|
err = StructuralError{"struct contains unexported fields", structType.Field(i).Name}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if structType.NumField() > 0 &&
|
if structType.NumField() > 0 &&
|
||||||
structType.Field(0).Type == rawContentsType {
|
structType.Field(0).Type == rawContentsType {
|
||||||
bytes := bytes[initOffset:offset]
|
bytes := bytes[initOffset:offset]
|
||||||
@@ -826,7 +990,9 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
if i == 0 && field.Type == rawContentsType {
|
if i == 0 && field.Type == rawContentsType {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag.Get("asn1")))
|
innerParams := parseFieldParameters(field.Tag.Get("asn1"))
|
||||||
|
innerParams.name = field.Name
|
||||||
|
innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, innerParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -842,7 +1008,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
reflect.Copy(val, reflect.ValueOf(innerBytes))
|
reflect.Copy(val, reflect.ValueOf(innerBytes))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
|
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem(), params.name)
|
||||||
if err1 == nil {
|
if err1 == nil {
|
||||||
val.Set(newSlice)
|
val.Set(newSlice)
|
||||||
}
|
}
|
||||||
@@ -851,34 +1017,47 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
|
|||||||
case reflect.String:
|
case reflect.String:
|
||||||
var v string
|
var v string
|
||||||
switch universalTag {
|
switch universalTag {
|
||||||
case tagPrintableString:
|
case TagPrintableString:
|
||||||
v, err = parsePrintableString(innerBytes)
|
v, err = parsePrintableString(innerBytes, params.name)
|
||||||
case tagIA5String:
|
case TagNumericString:
|
||||||
v, err = parseIA5String(innerBytes)
|
v, err = parseNumericString(innerBytes, params.name)
|
||||||
case tagT61String:
|
case TagIA5String:
|
||||||
|
v, err = parseIA5String(innerBytes, params.name)
|
||||||
|
case TagT61String:
|
||||||
v, err = parseT61String(innerBytes)
|
v, err = parseT61String(innerBytes)
|
||||||
case tagUTF8String:
|
case TagUTF8String:
|
||||||
v, err = parseUTF8String(innerBytes)
|
v, err = parseUTF8String(innerBytes)
|
||||||
case tagGeneralString:
|
case TagGeneralString:
|
||||||
// GeneralString is specified in ISO-2022/ECMA-35,
|
// GeneralString is specified in ISO-2022/ECMA-35,
|
||||||
// A brief review suggests that it includes structures
|
// A brief review suggests that it includes structures
|
||||||
// that allow the encoding to change midstring and
|
// that allow the encoding to change midstring and
|
||||||
// such. We give up and pass it as an 8-bit string.
|
// such. We give up and pass it as an 8-bit string.
|
||||||
v, err = parseT61String(innerBytes)
|
v, err = parseT61String(innerBytes)
|
||||||
default:
|
default:
|
||||||
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
|
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag), params.name}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
val.SetString(v)
|
val.SetString(v)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = StructuralError{"unsupported: " + v.Type().String()}
|
err = StructuralError{"unsupported: " + v.Type().String(), params.name}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canHaveDefaultValue reports whether k is a Kind that we will set a default
|
||||||
|
// value for. (A signed integer, essentially.)
|
||||||
|
func canHaveDefaultValue(k reflect.Kind) bool {
|
||||||
|
switch k {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// setDefaultValue is used to install a default value, from a tag string, into
|
// setDefaultValue is used to install a default value, from a tag string, into
|
||||||
// a Value. It is successful is the field was optional, even if a default value
|
// a Value. It is successful if the field was optional, even if a default value
|
||||||
// wasn't provided or it failed to install it into the Value.
|
// wasn't provided or it failed to install it into the Value.
|
||||||
func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
||||||
if !params.optional {
|
if !params.optional {
|
||||||
@@ -888,9 +1067,8 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
|||||||
if params.defaultValue == nil {
|
if params.defaultValue == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch val := v; val.Kind() {
|
if canHaveDefaultValue(v.Kind()) {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
v.SetInt(*params.defaultValue)
|
||||||
val.SetInt(*params.defaultValue)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -916,7 +1094,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
|||||||
//
|
//
|
||||||
// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time.
|
// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time.
|
||||||
//
|
//
|
||||||
// An ASN.1 PrintableString or IA5String can be written to a string.
|
// An ASN.1 PrintableString, IA5String, or NumericString can be written to a string.
|
||||||
//
|
//
|
||||||
// Any of the above ASN.1 values can be written to an interface{}.
|
// Any of the above ASN.1 values can be written to an interface{}.
|
||||||
// The value stored in the interface has the corresponding Go type.
|
// The value stored in the interface has the corresponding Go type.
|
||||||
@@ -931,13 +1109,20 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
|||||||
//
|
//
|
||||||
// The following tags on struct fields have special meaning to Unmarshal:
|
// The following tags on struct fields have special meaning to Unmarshal:
|
||||||
//
|
//
|
||||||
|
// application specifies that an APPLICATION tag is used
|
||||||
|
// default:x sets the default value for optional integer fields (only used if optional is also present)
|
||||||
|
// explicit specifies that an additional, explicit tag wraps the implicit one
|
||||||
// optional marks the field as ASN.1 OPTIONAL
|
// optional marks the field as ASN.1 OPTIONAL
|
||||||
// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
|
// set causes a SET, rather than a SEQUENCE type to be expected
|
||||||
// default:x sets the default value for optional integer fields
|
// tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
|
||||||
//
|
//
|
||||||
// If the type of the first field of a structure is RawContent then the raw
|
// If the type of the first field of a structure is RawContent then the raw
|
||||||
// ASN1 contents of the struct will be stored in it.
|
// ASN1 contents of the struct will be stored in it.
|
||||||
//
|
//
|
||||||
|
// If the type name of a slice element ends with "SET" then it's treated as if
|
||||||
|
// the "set" tag was set on it. This can be used with nested slices where a
|
||||||
|
// struct tag cannot be given.
|
||||||
|
//
|
||||||
// Other ASN.1 types are not supported; if it encounters them,
|
// Other ASN.1 types are not supported; if it encounters them,
|
||||||
// Unmarshal returns a parse error.
|
// Unmarshal returns a parse error.
|
||||||
func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
|
func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
|
||||||
86
vendor/github.com/google/certificate-transparency/go/asn1/common.go → vendor/github.com/google/certificate-transparency-go/asn1/common.go
generated
vendored
Executable file → Normal file
86
vendor/github.com/google/certificate-transparency/go/asn1/common.go → vendor/github.com/google/certificate-transparency-go/asn1/common.go
generated
vendored
Executable file → Normal file
@@ -18,29 +18,33 @@ import (
|
|||||||
|
|
||||||
// Here are some standard tags and classes
|
// Here are some standard tags and classes
|
||||||
|
|
||||||
|
// ASN.1 tags represent the type of the following object.
|
||||||
const (
|
const (
|
||||||
tagBoolean = 1
|
TagBoolean = 1
|
||||||
tagInteger = 2
|
TagInteger = 2
|
||||||
tagBitString = 3
|
TagBitString = 3
|
||||||
tagOctetString = 4
|
TagOctetString = 4
|
||||||
tagOID = 6
|
TagNull = 5
|
||||||
tagEnum = 10
|
TagOID = 6
|
||||||
tagUTF8String = 12
|
TagEnum = 10
|
||||||
tagSequence = 16
|
TagUTF8String = 12
|
||||||
tagSet = 17
|
TagSequence = 16
|
||||||
tagPrintableString = 19
|
TagSet = 17
|
||||||
tagT61String = 20
|
TagNumericString = 18
|
||||||
tagIA5String = 22
|
TagPrintableString = 19
|
||||||
tagUTCTime = 23
|
TagT61String = 20
|
||||||
tagGeneralizedTime = 24
|
TagIA5String = 22
|
||||||
tagGeneralString = 27
|
TagUTCTime = 23
|
||||||
|
TagGeneralizedTime = 24
|
||||||
|
TagGeneralString = 27
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ASN.1 class types represent the namespace of the tag.
|
||||||
const (
|
const (
|
||||||
classUniversal = 0
|
ClassUniversal = 0
|
||||||
classApplication = 1
|
ClassApplication = 1
|
||||||
classContextSpecific = 2
|
ClassContextSpecific = 2
|
||||||
classPrivate = 3
|
ClassPrivate = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
type tagAndLength struct {
|
type tagAndLength struct {
|
||||||
@@ -74,8 +78,10 @@ type fieldParameters struct {
|
|||||||
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
|
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
|
||||||
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
|
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
|
||||||
stringType int // the string tag to use when marshaling.
|
stringType int // the string tag to use when marshaling.
|
||||||
|
timeType int // the time tag to use when marshaling.
|
||||||
set bool // true iff this should be encoded as a SET
|
set bool // true iff this should be encoded as a SET
|
||||||
omitEmpty bool // true iff this should be omitted if empty when marshaling.
|
omitEmpty bool // true iff this should be omitted if empty when marshaling.
|
||||||
|
name string // name of field for better diagnostics
|
||||||
|
|
||||||
// Invariants:
|
// Invariants:
|
||||||
// if explicit is set, tag is non-nil.
|
// if explicit is set, tag is non-nil.
|
||||||
@@ -94,12 +100,18 @@ func parseFieldParameters(str string) (ret fieldParameters) {
|
|||||||
if ret.tag == nil {
|
if ret.tag == nil {
|
||||||
ret.tag = new(int)
|
ret.tag = new(int)
|
||||||
}
|
}
|
||||||
|
case part == "generalized":
|
||||||
|
ret.timeType = TagGeneralizedTime
|
||||||
|
case part == "utc":
|
||||||
|
ret.timeType = TagUTCTime
|
||||||
case part == "ia5":
|
case part == "ia5":
|
||||||
ret.stringType = tagIA5String
|
ret.stringType = TagIA5String
|
||||||
case part == "printable":
|
case part == "printable":
|
||||||
ret.stringType = tagPrintableString
|
ret.stringType = TagPrintableString
|
||||||
|
case part == "numeric":
|
||||||
|
ret.stringType = TagNumericString
|
||||||
case part == "utf8":
|
case part == "utf8":
|
||||||
ret.stringType = tagUTF8String
|
ret.stringType = TagUTF8String
|
||||||
case strings.HasPrefix(part, "default:"):
|
case strings.HasPrefix(part, "default:"):
|
||||||
i, err := strconv.ParseInt(part[8:], 10, 64)
|
i, err := strconv.ParseInt(part[8:], 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -128,36 +140,38 @@ func parseFieldParameters(str string) (ret fieldParameters) {
|
|||||||
|
|
||||||
// Given a reflected Go type, getUniversalType returns the default tag number
|
// Given a reflected Go type, getUniversalType returns the default tag number
|
||||||
// and expected compound flag.
|
// and expected compound flag.
|
||||||
func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
|
func getUniversalType(t reflect.Type) (matchAny bool, tagNumber int, isCompound, ok bool) {
|
||||||
switch t {
|
switch t {
|
||||||
|
case rawValueType:
|
||||||
|
return true, -1, false, true
|
||||||
case objectIdentifierType:
|
case objectIdentifierType:
|
||||||
return tagOID, false, true
|
return false, TagOID, false, true
|
||||||
case bitStringType:
|
case bitStringType:
|
||||||
return tagBitString, false, true
|
return false, TagBitString, false, true
|
||||||
case timeType:
|
case timeType:
|
||||||
return tagUTCTime, false, true
|
return false, TagUTCTime, false, true
|
||||||
case enumeratedType:
|
case enumeratedType:
|
||||||
return tagEnum, false, true
|
return false, TagEnum, false, true
|
||||||
case bigIntType:
|
case bigIntType:
|
||||||
return tagInteger, false, true
|
return false, TagInteger, false, true
|
||||||
}
|
}
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return tagBoolean, false, true
|
return false, TagBoolean, false, true
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
return tagInteger, false, true
|
return false, TagInteger, false, true
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return tagSequence, true, true
|
return false, TagSequence, true, true
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if t.Elem().Kind() == reflect.Uint8 {
|
if t.Elem().Kind() == reflect.Uint8 {
|
||||||
return tagOctetString, false, true
|
return false, TagOctetString, false, true
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(t.Name(), "SET") {
|
if strings.HasSuffix(t.Name(), "SET") {
|
||||||
return tagSet, true, true
|
return false, TagSet, true, true
|
||||||
}
|
}
|
||||||
return tagSequence, true, true
|
return false, TagSequence, true, true
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return tagPrintableString, false, true
|
return false, TagPrintableString, false, true
|
||||||
}
|
}
|
||||||
return 0, false, false
|
return false, 0, false, false
|
||||||
}
|
}
|
||||||
689
vendor/github.com/google/certificate-transparency-go/asn1/marshal.go
generated
vendored
Normal file
689
vendor/github.com/google/certificate-transparency-go/asn1/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,689 @@
|
|||||||
|
// 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 LICENSE file.
|
||||||
|
|
||||||
|
package asn1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
byte00Encoder encoder = byteEncoder(0x00)
|
||||||
|
byteFFEncoder encoder = byteEncoder(0xff)
|
||||||
|
)
|
||||||
|
|
||||||
|
// encoder represents an ASN.1 element that is waiting to be marshaled.
|
||||||
|
type encoder interface {
|
||||||
|
// Len returns the number of bytes needed to marshal this element.
|
||||||
|
Len() int
|
||||||
|
// Encode encodes this element by writing Len() bytes to dst.
|
||||||
|
Encode(dst []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteEncoder byte
|
||||||
|
|
||||||
|
func (c byteEncoder) Len() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c byteEncoder) Encode(dst []byte) {
|
||||||
|
dst[0] = byte(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
type bytesEncoder []byte
|
||||||
|
|
||||||
|
func (b bytesEncoder) Len() int {
|
||||||
|
return len(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bytesEncoder) Encode(dst []byte) {
|
||||||
|
if copy(dst, b) != len(b) {
|
||||||
|
panic("internal error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type stringEncoder string
|
||||||
|
|
||||||
|
func (s stringEncoder) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s stringEncoder) Encode(dst []byte) {
|
||||||
|
if copy(dst, s) != len(s) {
|
||||||
|
panic("internal error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiEncoder []encoder
|
||||||
|
|
||||||
|
func (m multiEncoder) Len() int {
|
||||||
|
var size int
|
||||||
|
for _, e := range m {
|
||||||
|
size += e.Len()
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiEncoder) Encode(dst []byte) {
|
||||||
|
var off int
|
||||||
|
for _, e := range m {
|
||||||
|
e.Encode(dst[off:])
|
||||||
|
off += e.Len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type taggedEncoder struct {
|
||||||
|
// scratch contains temporary space for encoding the tag and length of
|
||||||
|
// an element in order to avoid extra allocations.
|
||||||
|
scratch [8]byte
|
||||||
|
tag encoder
|
||||||
|
body encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *taggedEncoder) Len() int {
|
||||||
|
return t.tag.Len() + t.body.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *taggedEncoder) Encode(dst []byte) {
|
||||||
|
t.tag.Encode(dst)
|
||||||
|
t.body.Encode(dst[t.tag.Len():])
|
||||||
|
}
|
||||||
|
|
||||||
|
type int64Encoder int64
|
||||||
|
|
||||||
|
func (i int64Encoder) Len() int {
|
||||||
|
n := 1
|
||||||
|
|
||||||
|
for i > 127 {
|
||||||
|
n++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
for i < -128 {
|
||||||
|
n++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i int64Encoder) Encode(dst []byte) {
|
||||||
|
n := i.Len()
|
||||||
|
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
dst[j] = byte(i >> uint((n-1-j)*8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func base128IntLength(n int64) int {
|
||||||
|
if n == 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
l := 0
|
||||||
|
for i := n; i > 0; i >>= 7 {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBase128Int(dst []byte, n int64) []byte {
|
||||||
|
l := base128IntLength(n)
|
||||||
|
|
||||||
|
for i := l - 1; i >= 0; i-- {
|
||||||
|
o := byte(n >> uint(i*7))
|
||||||
|
o &= 0x7f
|
||||||
|
if i != 0 {
|
||||||
|
o |= 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = append(dst, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBigInt(n *big.Int, fieldName string) (encoder, error) {
|
||||||
|
if n == nil {
|
||||||
|
return nil, StructuralError{"empty integer", fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Sign() < 0 {
|
||||||
|
// A negative number has to be converted to two's-complement
|
||||||
|
// form. So we'll invert and subtract 1. If the
|
||||||
|
// most-significant-bit isn't set then we'll need to pad the
|
||||||
|
// beginning with 0xff in order to keep the number negative.
|
||||||
|
nMinus1 := new(big.Int).Neg(n)
|
||||||
|
nMinus1.Sub(nMinus1, bigOne)
|
||||||
|
bytes := nMinus1.Bytes()
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] ^= 0xff
|
||||||
|
}
|
||||||
|
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
|
||||||
|
return multiEncoder([]encoder{byteFFEncoder, bytesEncoder(bytes)}), nil
|
||||||
|
}
|
||||||
|
return bytesEncoder(bytes), nil
|
||||||
|
} else if n.Sign() == 0 {
|
||||||
|
// Zero is written as a single 0 zero rather than no bytes.
|
||||||
|
return byte00Encoder, nil
|
||||||
|
} else {
|
||||||
|
bytes := n.Bytes()
|
||||||
|
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
|
||||||
|
// We'll have to pad this with 0x00 in order to stop it
|
||||||
|
// looking like a negative number.
|
||||||
|
return multiEncoder([]encoder{byte00Encoder, bytesEncoder(bytes)}), nil
|
||||||
|
}
|
||||||
|
return bytesEncoder(bytes), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendLength(dst []byte, i int) []byte {
|
||||||
|
n := lengthLength(i)
|
||||||
|
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
dst = append(dst, byte(i>>uint((n-1)*8)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func lengthLength(i int) (numBytes int) {
|
||||||
|
numBytes = 1
|
||||||
|
for i > 255 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTagAndLength(dst []byte, t tagAndLength) []byte {
|
||||||
|
b := uint8(t.class) << 6
|
||||||
|
if t.isCompound {
|
||||||
|
b |= 0x20
|
||||||
|
}
|
||||||
|
if t.tag >= 31 {
|
||||||
|
b |= 0x1f
|
||||||
|
dst = append(dst, b)
|
||||||
|
dst = appendBase128Int(dst, int64(t.tag))
|
||||||
|
} else {
|
||||||
|
b |= uint8(t.tag)
|
||||||
|
dst = append(dst, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.length >= 128 {
|
||||||
|
l := lengthLength(t.length)
|
||||||
|
dst = append(dst, 0x80|byte(l))
|
||||||
|
dst = appendLength(dst, t.length)
|
||||||
|
} else {
|
||||||
|
dst = append(dst, byte(t.length))
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
type bitStringEncoder BitString
|
||||||
|
|
||||||
|
func (b bitStringEncoder) Len() int {
|
||||||
|
return len(b.Bytes) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b bitStringEncoder) Encode(dst []byte) {
|
||||||
|
dst[0] = byte((8 - b.BitLength%8) % 8)
|
||||||
|
if copy(dst[1:], b.Bytes) != len(b.Bytes) {
|
||||||
|
panic("internal error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type oidEncoder []int
|
||||||
|
|
||||||
|
func (oid oidEncoder) Len() int {
|
||||||
|
l := base128IntLength(int64(oid[0]*40 + oid[1]))
|
||||||
|
for i := 2; i < len(oid); i++ {
|
||||||
|
l += base128IntLength(int64(oid[i]))
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oid oidEncoder) Encode(dst []byte) {
|
||||||
|
dst = appendBase128Int(dst[:0], int64(oid[0]*40+oid[1]))
|
||||||
|
for i := 2; i < len(oid); i++ {
|
||||||
|
dst = appendBase128Int(dst, int64(oid[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeObjectIdentifier(oid []int, fieldName string) (e encoder, err error) {
|
||||||
|
if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
|
||||||
|
return nil, StructuralError{"invalid object identifier", fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oidEncoder(oid), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePrintableString(s, fieldName string) (e encoder, err error) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
// The asterisk is often used in PrintableString, even though
|
||||||
|
// it is invalid. If a PrintableString was specifically
|
||||||
|
// requested then the asterisk is permitted by this code.
|
||||||
|
// Ampersand is allowed in parsing due a handful of CA
|
||||||
|
// certificates, however when making new certificates
|
||||||
|
// it is rejected.
|
||||||
|
if !isPrintable(s[i], allowAsterisk, rejectAmpersand) {
|
||||||
|
return nil, StructuralError{"PrintableString contains invalid character", fieldName}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringEncoder(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeIA5String(s, fieldName string) (e encoder, err error) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] > 127 {
|
||||||
|
return nil, StructuralError{"IA5String contains invalid character", fieldName}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringEncoder(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNumericString(s string, fieldName string) (e encoder, err error) {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if !isNumeric(s[i]) {
|
||||||
|
return nil, StructuralError{"NumericString contains invalid character", fieldName}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringEncoder(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeUTF8String(s string) encoder {
|
||||||
|
return stringEncoder(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTwoDigits(dst []byte, v int) []byte {
|
||||||
|
return append(dst, byte('0'+(v/10)%10), byte('0'+v%10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFourDigits(dst []byte, v int) []byte {
|
||||||
|
var bytes [4]byte
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[3-i] = '0' + byte(v%10)
|
||||||
|
v /= 10
|
||||||
|
}
|
||||||
|
return append(dst, bytes[:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func outsideUTCRange(t time.Time) bool {
|
||||||
|
year := t.Year()
|
||||||
|
return year < 1950 || year >= 2050
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeUTCTime(t time.Time, fieldName string) (e encoder, err error) {
|
||||||
|
dst := make([]byte, 0, 18)
|
||||||
|
|
||||||
|
dst, err = appendUTCTime(dst, t, fieldName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesEncoder(dst), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeGeneralizedTime(t time.Time, fieldName string) (e encoder, err error) {
|
||||||
|
dst := make([]byte, 0, 20)
|
||||||
|
|
||||||
|
dst, err = appendGeneralizedTime(dst, t, fieldName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesEncoder(dst), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUTCTime(dst []byte, t time.Time, fieldName string) (ret []byte, err error) {
|
||||||
|
year := t.Year()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case 1950 <= year && year < 2000:
|
||||||
|
dst = appendTwoDigits(dst, year-1900)
|
||||||
|
case 2000 <= year && year < 2050:
|
||||||
|
dst = appendTwoDigits(dst, year-2000)
|
||||||
|
default:
|
||||||
|
return nil, StructuralError{"cannot represent time as UTCTime", fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
return appendTimeCommon(dst, t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendGeneralizedTime(dst []byte, t time.Time, fieldName string) (ret []byte, err error) {
|
||||||
|
year := t.Year()
|
||||||
|
if year < 0 || year > 9999 {
|
||||||
|
return nil, StructuralError{"cannot represent time as GeneralizedTime", fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = appendFourDigits(dst, year)
|
||||||
|
|
||||||
|
return appendTimeCommon(dst, t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTimeCommon(dst []byte, t time.Time) []byte {
|
||||||
|
_, month, day := t.Date()
|
||||||
|
|
||||||
|
dst = appendTwoDigits(dst, int(month))
|
||||||
|
dst = appendTwoDigits(dst, day)
|
||||||
|
|
||||||
|
hour, min, sec := t.Clock()
|
||||||
|
|
||||||
|
dst = appendTwoDigits(dst, hour)
|
||||||
|
dst = appendTwoDigits(dst, min)
|
||||||
|
dst = appendTwoDigits(dst, sec)
|
||||||
|
|
||||||
|
_, offset := t.Zone()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case offset/60 == 0:
|
||||||
|
return append(dst, 'Z')
|
||||||
|
case offset > 0:
|
||||||
|
dst = append(dst, '+')
|
||||||
|
case offset < 0:
|
||||||
|
dst = append(dst, '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetMinutes := offset / 60
|
||||||
|
if offsetMinutes < 0 {
|
||||||
|
offsetMinutes = -offsetMinutes
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = appendTwoDigits(dst, offsetMinutes/60)
|
||||||
|
dst = appendTwoDigits(dst, offsetMinutes%60)
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripTagAndLength(in []byte) []byte {
|
||||||
|
_, offset, err := parseTagAndLength(in, 0, "")
|
||||||
|
if err != nil {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
return in[offset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error) {
|
||||||
|
switch value.Type() {
|
||||||
|
case flagType:
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
case timeType:
|
||||||
|
t := value.Interface().(time.Time)
|
||||||
|
if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
|
||||||
|
return makeGeneralizedTime(t, params.name)
|
||||||
|
}
|
||||||
|
return makeUTCTime(t, params.name)
|
||||||
|
case bitStringType:
|
||||||
|
return bitStringEncoder(value.Interface().(BitString)), nil
|
||||||
|
case objectIdentifierType:
|
||||||
|
return makeObjectIdentifier(value.Interface().(ObjectIdentifier), params.name)
|
||||||
|
case bigIntType:
|
||||||
|
return makeBigInt(value.Interface().(*big.Int), params.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := value; v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
return byteFFEncoder, nil
|
||||||
|
}
|
||||||
|
return byte00Encoder, nil
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return int64Encoder(v.Int()), nil
|
||||||
|
case reflect.Struct:
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
if t.Field(i).PkgPath != "" {
|
||||||
|
return nil, StructuralError{"struct contains unexported fields", t.Field(i).Name}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startingField := 0
|
||||||
|
|
||||||
|
n := t.NumField()
|
||||||
|
if n == 0 {
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the first element of the structure is a non-empty
|
||||||
|
// RawContents, then we don't bother serializing the rest.
|
||||||
|
if t.Field(0).Type == rawContentsType {
|
||||||
|
s := v.Field(0)
|
||||||
|
if s.Len() > 0 {
|
||||||
|
bytes := s.Bytes()
|
||||||
|
/* The RawContents will contain the tag and
|
||||||
|
* length fields but we'll also be writing
|
||||||
|
* those ourselves, so we strip them out of
|
||||||
|
* bytes */
|
||||||
|
return bytesEncoder(stripTagAndLength(bytes)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
startingField = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch n1 := n - startingField; n1 {
|
||||||
|
case 0:
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
case 1:
|
||||||
|
return makeField(v.Field(startingField), parseFieldParameters(t.Field(startingField).Tag.Get("asn1")))
|
||||||
|
default:
|
||||||
|
m := make([]encoder, n1)
|
||||||
|
for i := 0; i < n1; i++ {
|
||||||
|
m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1")))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return multiEncoder(m), nil
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
sliceType := v.Type()
|
||||||
|
if sliceType.Elem().Kind() == reflect.Uint8 {
|
||||||
|
return bytesEncoder(v.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var fp fieldParameters
|
||||||
|
|
||||||
|
switch l := v.Len(); l {
|
||||||
|
case 0:
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
case 1:
|
||||||
|
return makeField(v.Index(0), fp)
|
||||||
|
default:
|
||||||
|
m := make([]encoder, l)
|
||||||
|
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
m[i], err = makeField(v.Index(i), fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return multiEncoder(m), nil
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
switch params.stringType {
|
||||||
|
case TagIA5String:
|
||||||
|
return makeIA5String(v.String(), params.name)
|
||||||
|
case TagPrintableString:
|
||||||
|
return makePrintableString(v.String(), params.name)
|
||||||
|
case TagNumericString:
|
||||||
|
return makeNumericString(v.String(), params.name)
|
||||||
|
default:
|
||||||
|
return makeUTF8String(v.String()), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, StructuralError{"unknown Go type", params.name}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
|
||||||
|
if !v.IsValid() {
|
||||||
|
return nil, fmt.Errorf("asn1: cannot marshal nil value")
|
||||||
|
}
|
||||||
|
// If the field is an interface{} then recurse into it.
|
||||||
|
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
|
||||||
|
return makeField(v.Elem(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
|
||||||
|
defaultValue := reflect.New(v.Type()).Elem()
|
||||||
|
defaultValue.SetInt(*params.defaultValue)
|
||||||
|
|
||||||
|
if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no default value is given then the zero value for the type is
|
||||||
|
// assumed to be the default value. This isn't obviously the correct
|
||||||
|
// behavior, but it's what Go has traditionally done.
|
||||||
|
if params.optional && params.defaultValue == nil {
|
||||||
|
if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
|
||||||
|
return bytesEncoder(nil), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Type() == rawValueType {
|
||||||
|
rv := v.Interface().(RawValue)
|
||||||
|
if len(rv.FullBytes) != 0 {
|
||||||
|
return bytesEncoder(rv.FullBytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := new(taggedEncoder)
|
||||||
|
|
||||||
|
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}))
|
||||||
|
t.body = bytesEncoder(rv.Bytes)
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
matchAny, tag, isCompound, ok := getUniversalType(v.Type())
|
||||||
|
if !ok || matchAny {
|
||||||
|
return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type()), params.name}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.timeType != 0 && tag != TagUTCTime {
|
||||||
|
return nil, StructuralError{"explicit time type given to non-time member", params.name}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.stringType != 0 && tag != TagPrintableString {
|
||||||
|
return nil, StructuralError{"explicit string type given to non-string member", params.name}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case TagPrintableString:
|
||||||
|
if params.stringType == 0 {
|
||||||
|
// This is a string without an explicit string type. We'll use
|
||||||
|
// a PrintableString if the character set in the string is
|
||||||
|
// sufficiently limited, otherwise we'll use a UTF8String.
|
||||||
|
for _, r := range v.String() {
|
||||||
|
if r >= utf8.RuneSelf || !isPrintable(byte(r), rejectAsterisk, rejectAmpersand) {
|
||||||
|
if !utf8.ValidString(v.String()) {
|
||||||
|
return nil, errors.New("asn1: string not valid UTF-8")
|
||||||
|
}
|
||||||
|
tag = TagUTF8String
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tag = params.stringType
|
||||||
|
}
|
||||||
|
case TagUTCTime:
|
||||||
|
if params.timeType == TagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
|
||||||
|
tag = TagGeneralizedTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.set {
|
||||||
|
if tag != TagSequence {
|
||||||
|
return nil, StructuralError{"non sequence tagged as set", params.name}
|
||||||
|
}
|
||||||
|
tag = TagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
t := new(taggedEncoder)
|
||||||
|
|
||||||
|
t.body, err = makeBody(v, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyLen := t.body.Len()
|
||||||
|
|
||||||
|
class := ClassUniversal
|
||||||
|
if params.tag != nil {
|
||||||
|
if params.application {
|
||||||
|
class = ClassApplication
|
||||||
|
} else {
|
||||||
|
class = ClassContextSpecific
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.explicit {
|
||||||
|
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound}))
|
||||||
|
|
||||||
|
tt := new(taggedEncoder)
|
||||||
|
|
||||||
|
tt.body = t
|
||||||
|
|
||||||
|
tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{
|
||||||
|
class: class,
|
||||||
|
tag: *params.tag,
|
||||||
|
length: bodyLen + t.tag.Len(),
|
||||||
|
isCompound: true,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return tt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// implicit tag.
|
||||||
|
tag = *params.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal returns the ASN.1 encoding of val.
|
||||||
|
//
|
||||||
|
// In addition to the struct tags recognised by Unmarshal, the following can be
|
||||||
|
// used:
|
||||||
|
//
|
||||||
|
// ia5: causes strings to be marshaled as ASN.1, IA5String values
|
||||||
|
// omitempty: causes empty slices to be skipped
|
||||||
|
// printable: causes strings to be marshaled as ASN.1, PrintableString values
|
||||||
|
// utf8: causes strings to be marshaled as ASN.1, UTF8String values
|
||||||
|
// utc: causes time.Time to be marshaled as ASN.1, UTCTime values
|
||||||
|
// generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values
|
||||||
|
func Marshal(val interface{}) ([]byte, error) {
|
||||||
|
return MarshalWithParams(val, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalWithParams allows field parameters to be specified for the
|
||||||
|
// top-level element. The form of the params is the same as the field tags.
|
||||||
|
func MarshalWithParams(val interface{}, params string) ([]byte, error) {
|
||||||
|
e, err := makeField(reflect.ValueOf(val), parseFieldParameters(params))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b := make([]byte, e.Len())
|
||||||
|
e.Encode(b)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
38
vendor/github.com/google/certificate-transparency-go/client/BUILD
generated
vendored
Normal file
38
vendor/github.com/google/certificate-transparency-go/client/BUILD
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"getentries.go",
|
||||||
|
"logclient.go",
|
||||||
|
"multilog.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/google/certificate-transparency-go/client",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/github.com/golang/protobuf/proto:go_default_library",
|
||||||
|
"//vendor/github.com/golang/protobuf/ptypes:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/client/configpb:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/jsonclient:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/tls:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/x509:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/client/configpb:all-srcs",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
35
vendor/github.com/google/certificate-transparency-go/client/configpb/BUILD
generated
vendored
Normal file
35
vendor/github.com/google/certificate-transparency-go/client/configpb/BUILD
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "go_default_library_protos",
|
||||||
|
srcs = ["multilog.proto"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"gen.go",
|
||||||
|
"multilog.pb.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/google/certificate-transparency-go/client/configpb",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/github.com/golang/protobuf/proto:go_default_library",
|
||||||
|
"//vendor/github.com/golang/protobuf/ptypes/timestamp:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
17
vendor/github.com/google/certificate-transparency-go/client/configpb/gen.go
generated
vendored
Normal file
17
vendor/github.com/google/certificate-transparency-go/client/configpb/gen.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package configpb
|
||||||
|
|
||||||
|
//go:generate protoc -I=. -I=$GOPATH/src --go_out=:. multilog.proto
|
||||||
124
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.pb.go
generated
vendored
Normal file
124
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.pb.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: multilog.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package configpb is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
multilog.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
TemporalLogConfig
|
||||||
|
LogShardConfig
|
||||||
|
*/
|
||||||
|
package configpb
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// TemporalLogConfig is a set of LogShardConfig messages, whose
|
||||||
|
// time limits should be contiguous.
|
||||||
|
type TemporalLogConfig struct {
|
||||||
|
Shard []*LogShardConfig `protobuf:"bytes,1,rep,name=shard" json:"shard,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TemporalLogConfig) Reset() { *m = TemporalLogConfig{} }
|
||||||
|
func (m *TemporalLogConfig) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*TemporalLogConfig) ProtoMessage() {}
|
||||||
|
func (*TemporalLogConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *TemporalLogConfig) GetShard() []*LogShardConfig {
|
||||||
|
if m != nil {
|
||||||
|
return m.Shard
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogShardConfig describes the acceptable date range for a single shard of a temporal
|
||||||
|
// log.
|
||||||
|
type LogShardConfig struct {
|
||||||
|
Uri string `protobuf:"bytes,1,opt,name=uri" json:"uri,omitempty"`
|
||||||
|
// The log's public key in DER-encoded PKIX form.
|
||||||
|
PublicKeyDer []byte `protobuf:"bytes,2,opt,name=public_key_der,json=publicKeyDer,proto3" json:"public_key_der,omitempty"`
|
||||||
|
// not_after_start defines the start of the range of acceptable NotAfter
|
||||||
|
// values, inclusive.
|
||||||
|
// Leaving this unset implies no lower bound to the range.
|
||||||
|
NotAfterStart *google_protobuf.Timestamp `protobuf:"bytes,3,opt,name=not_after_start,json=notAfterStart" json:"not_after_start,omitempty"`
|
||||||
|
// not_after_limit defines the end of the range of acceptable NotAfter values,
|
||||||
|
// exclusive.
|
||||||
|
// Leaving this unset implies no upper bound to the range.
|
||||||
|
NotAfterLimit *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=not_after_limit,json=notAfterLimit" json:"not_after_limit,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LogShardConfig) Reset() { *m = LogShardConfig{} }
|
||||||
|
func (m *LogShardConfig) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*LogShardConfig) ProtoMessage() {}
|
||||||
|
func (*LogShardConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *LogShardConfig) GetUri() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Uri
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LogShardConfig) GetPublicKeyDer() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.PublicKeyDer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LogShardConfig) GetNotAfterStart() *google_protobuf.Timestamp {
|
||||||
|
if m != nil {
|
||||||
|
return m.NotAfterStart
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *LogShardConfig) GetNotAfterLimit() *google_protobuf.Timestamp {
|
||||||
|
if m != nil {
|
||||||
|
return m.NotAfterLimit
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*TemporalLogConfig)(nil), "configpb.TemporalLogConfig")
|
||||||
|
proto.RegisterType((*LogShardConfig)(nil), "configpb.LogShardConfig")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("multilog.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 241 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x8f, 0xb1, 0x4e, 0xc3, 0x30,
|
||||||
|
0x14, 0x45, 0x65, 0x02, 0x08, 0xdc, 0x12, 0xc0, 0x93, 0xd5, 0x85, 0xa8, 0x62, 0xc8, 0xe4, 0x4a,
|
||||||
|
0xe5, 0x0b, 0xa0, 0x6c, 0x64, 0x4a, 0xbb, 0x47, 0x4e, 0xeb, 0x18, 0x0b, 0x3b, 0xcf, 0x72, 0x5e,
|
||||||
|
0x86, 0xfe, 0x25, 0x9f, 0x84, 0x1c, 0x2b, 0x43, 0x37, 0xb6, 0xa7, 0x77, 0xcf, 0xb9, 0xd2, 0xa5,
|
||||||
|
0xb9, 0x1b, 0x2d, 0x1a, 0x0b, 0x5a, 0xf8, 0x00, 0x08, 0xec, 0xee, 0x08, 0x7d, 0x67, 0xb4, 0x6f,
|
||||||
|
0x57, 0x2f, 0x1a, 0x40, 0x5b, 0xb5, 0x99, 0xfe, 0xed, 0xd8, 0x6d, 0xd0, 0x38, 0x35, 0xa0, 0x74,
|
||||||
|
0x3e, 0xa1, 0xeb, 0x1d, 0x7d, 0x3e, 0x28, 0xe7, 0x21, 0x48, 0x5b, 0x81, 0xde, 0x4d, 0x1e, 0x13,
|
||||||
|
0xf4, 0x66, 0xf8, 0x96, 0xe1, 0xc4, 0x49, 0x91, 0x95, 0x8b, 0x2d, 0x17, 0x73, 0x9f, 0xa8, 0x40,
|
||||||
|
0xef, 0x63, 0x92, 0xc0, 0x3a, 0x61, 0xeb, 0x5f, 0x42, 0xf3, 0xcb, 0x84, 0x3d, 0xd1, 0x6c, 0x0c,
|
||||||
|
0x86, 0x93, 0x82, 0x94, 0xf7, 0x75, 0x3c, 0xd9, 0x2b, 0xcd, 0xfd, 0xd8, 0x5a, 0x73, 0x6c, 0x7e,
|
||||||
|
0xd4, 0xb9, 0x39, 0xa9, 0xc0, 0xaf, 0x0a, 0x52, 0x2e, 0xeb, 0x65, 0xfa, 0x7e, 0xa9, 0xf3, 0xa7,
|
||||||
|
0x0a, 0xec, 0x83, 0x3e, 0xf6, 0x80, 0x8d, 0xec, 0x50, 0x85, 0x66, 0x40, 0x19, 0x90, 0x67, 0x05,
|
||||||
|
0x29, 0x17, 0xdb, 0x95, 0x48, 0x53, 0xc4, 0x3c, 0x45, 0x1c, 0xe6, 0x29, 0xf5, 0x43, 0x0f, 0xf8,
|
||||||
|
0x1e, 0x8d, 0x7d, 0x14, 0x2e, 0x3b, 0xac, 0x71, 0x06, 0xf9, 0xf5, 0xff, 0x3b, 0xaa, 0x28, 0xb4,
|
||||||
|
0xb7, 0x13, 0xf2, 0xf6, 0x17, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xd9, 0x50, 0x5b, 0x5b, 0x01, 0x00,
|
||||||
|
0x00,
|
||||||
|
}
|
||||||
43
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.proto
generated
vendored
Normal file
43
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.proto
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package configpb;
|
||||||
|
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
// TemporalLogConfig is a set of LogShardConfig messages, whose
|
||||||
|
// time limits should be contiguous.
|
||||||
|
message TemporalLogConfig {
|
||||||
|
repeated LogShardConfig shard = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogShardConfig describes the acceptable date range for a single shard of a temporal
|
||||||
|
// log.
|
||||||
|
message LogShardConfig {
|
||||||
|
string uri = 1;
|
||||||
|
|
||||||
|
// The log's public key in DER-encoded PKIX form.
|
||||||
|
bytes public_key_der = 2;
|
||||||
|
|
||||||
|
// not_after_start defines the start of the range of acceptable NotAfter
|
||||||
|
// values, inclusive.
|
||||||
|
// Leaving this unset implies no lower bound to the range.
|
||||||
|
google.protobuf.Timestamp not_after_start = 3;
|
||||||
|
// not_after_limit defines the end of the range of acceptable NotAfter values,
|
||||||
|
// exclusive.
|
||||||
|
// Leaving this unset implies no upper bound to the range.
|
||||||
|
google.protobuf.Timestamp not_after_limit = 4;
|
||||||
|
}
|
||||||
75
vendor/github.com/google/certificate-transparency-go/client/getentries.go
generated
vendored
Normal file
75
vendor/github.com/google/certificate-transparency-go/client/getentries.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
ct "github.com/google/certificate-transparency-go"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetRawEntries exposes the /ct/v1/get-entries result with only the JSON parsing done.
|
||||||
|
func (c *LogClient) GetRawEntries(ctx context.Context, start, end int64) (*ct.GetEntriesResponse, error) {
|
||||||
|
if end < 0 {
|
||||||
|
return nil, errors.New("end should be >= 0")
|
||||||
|
}
|
||||||
|
if end < start {
|
||||||
|
return nil, errors.New("start should be <= end")
|
||||||
|
}
|
||||||
|
|
||||||
|
params := map[string]string{
|
||||||
|
"start": strconv.FormatInt(start, 10),
|
||||||
|
"end": strconv.FormatInt(end, 10),
|
||||||
|
}
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp ct.GetEntriesResponse
|
||||||
|
httpRsp, body, err := c.GetAndParse(ctx, ct.GetEntriesPath, params, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEntries attempts to retrieve the entries in the sequence [start, end] from the CT log server
|
||||||
|
// (RFC6962 s4.6) as parsed [pre-]certificates for convenience, held in a slice of ct.LogEntry structures.
|
||||||
|
// However, this does mean that any certificate parsing failures will cause a failure of the whole
|
||||||
|
// retrieval operation; for more robust retrieval of parsed certificates, use GetRawEntries() and invoke
|
||||||
|
// ct.LogEntryFromLeaf() on each individual entry.
|
||||||
|
func (c *LogClient) GetEntries(ctx context.Context, start, end int64) ([]ct.LogEntry, error) {
|
||||||
|
resp, err := c.GetRawEntries(ctx, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries := make([]ct.LogEntry, len(resp.Entries))
|
||||||
|
for i, entry := range resp.Entries {
|
||||||
|
index := start + int64(i)
|
||||||
|
logEntry, err := ct.LogEntryFromLeaf(index, &entry)
|
||||||
|
if _, ok := err.(x509.NonFatalErrors); !ok && err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries[i] = *logEntry
|
||||||
|
}
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
283
vendor/github.com/google/certificate-transparency-go/client/logclient.go
generated
vendored
Normal file
283
vendor/github.com/google/certificate-transparency-go/client/logclient.go
generated
vendored
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package client is a CT log client implementation and contains types and code
|
||||||
|
// for interacting with RFC6962-compliant CT Log instances.
|
||||||
|
// See http://tools.ietf.org/html/rfc6962 for details
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
ct "github.com/google/certificate-transparency-go"
|
||||||
|
"github.com/google/certificate-transparency-go/jsonclient"
|
||||||
|
"github.com/google/certificate-transparency-go/tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogClient represents a client for a given CT Log instance
|
||||||
|
type LogClient struct {
|
||||||
|
jsonclient.JSONClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// New constructs a new LogClient instance.
|
||||||
|
// |uri| is the base URI of the CT log instance to interact with, e.g.
|
||||||
|
// http://ct.googleapis.com/pilot
|
||||||
|
// |hc| is the underlying client to be used for HTTP requests to the CT log.
|
||||||
|
// |opts| can be used to provide a customer logger interface and a public key
|
||||||
|
// for signature verification.
|
||||||
|
func New(uri string, hc *http.Client, opts jsonclient.Options) (*LogClient, error) {
|
||||||
|
logClient, err := jsonclient.New(uri, hc, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &LogClient{*logClient}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RspError represents an error that occurred when processing a response from a server,
|
||||||
|
// and also includes key details from the http.Response that triggered the error.
|
||||||
|
type RspError struct {
|
||||||
|
Err error
|
||||||
|
StatusCode int
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error formats the RspError instance, focusing on the error.
|
||||||
|
func (e RspError) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to add |chain| to the log, using the api end-point specified by
|
||||||
|
// |path|. If provided context expires before submission is complete an
|
||||||
|
// error will be returned.
|
||||||
|
func (c *LogClient) addChainWithRetry(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
var resp ct.AddChainResponse
|
||||||
|
var req ct.AddChainRequest
|
||||||
|
for _, link := range chain {
|
||||||
|
req.Chain = append(req.Chain, link.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRsp, body, err := c.PostAndParseWithRetry(ctx, path, &req, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ds ct.DigitallySigned
|
||||||
|
if rest, err := tls.Unmarshal(resp.Signature, &ds); err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, RspError{
|
||||||
|
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||||
|
StatusCode: httpRsp.StatusCode,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exts, err := base64.StdEncoding.DecodeString(resp.Extensions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, RspError{
|
||||||
|
Err: fmt.Errorf("invalid base64 data in Extensions (%q): %v", resp.Extensions, err),
|
||||||
|
StatusCode: httpRsp.StatusCode,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var logID ct.LogID
|
||||||
|
copy(logID.KeyID[:], resp.ID)
|
||||||
|
sct := &ct.SignedCertificateTimestamp{
|
||||||
|
SCTVersion: resp.SCTVersion,
|
||||||
|
LogID: logID,
|
||||||
|
Timestamp: resp.Timestamp,
|
||||||
|
Extensions: ct.CTExtensions(exts),
|
||||||
|
Signature: ds,
|
||||||
|
}
|
||||||
|
if err := c.VerifySCTSignature(*sct, ctype, chain); err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return sct, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddChain adds the (DER represented) X509 |chain| to the log.
|
||||||
|
func (c *LogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
return c.addChainWithRetry(ctx, ct.X509LogEntryType, ct.AddChainPath, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPreChain adds the (DER represented) Precertificate |chain| to the log.
|
||||||
|
func (c *LogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
return c.addChainWithRetry(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddJSON submits arbitrary data to to XJSON server.
|
||||||
|
func (c *LogClient) AddJSON(ctx context.Context, data interface{}) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
req := ct.AddJSONRequest{Data: data}
|
||||||
|
var resp ct.AddChainResponse
|
||||||
|
httpRsp, body, err := c.PostAndParse(ctx, ct.AddJSONPath, &req, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var ds ct.DigitallySigned
|
||||||
|
if rest, err := tls.Unmarshal(resp.Signature, &ds); err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, RspError{
|
||||||
|
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||||
|
StatusCode: httpRsp.StatusCode,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var logID ct.LogID
|
||||||
|
copy(logID.KeyID[:], resp.ID)
|
||||||
|
return &ct.SignedCertificateTimestamp{
|
||||||
|
SCTVersion: resp.SCTVersion,
|
||||||
|
LogID: logID,
|
||||||
|
Timestamp: resp.Timestamp,
|
||||||
|
Extensions: ct.CTExtensions(resp.Extensions),
|
||||||
|
Signature: ds,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSTH retrieves the current STH from the log.
|
||||||
|
// Returns a populated SignedTreeHead, or a non-nil error (which may be of type
|
||||||
|
// RspError if a raw http.Response is available).
|
||||||
|
func (c *LogClient) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) {
|
||||||
|
var resp ct.GetSTHResponse
|
||||||
|
httpRsp, body, err := c.GetAndParse(ctx, ct.GetSTHPath, nil, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sth := ct.SignedTreeHead{
|
||||||
|
TreeSize: resp.TreeSize,
|
||||||
|
Timestamp: resp.Timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.SHA256RootHash) != sha256.Size {
|
||||||
|
return nil, RspError{
|
||||||
|
Err: fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(resp.SHA256RootHash)),
|
||||||
|
StatusCode: httpRsp.StatusCode,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy(sth.SHA256RootHash[:], resp.SHA256RootHash)
|
||||||
|
|
||||||
|
var ds ct.DigitallySigned
|
||||||
|
if rest, err := tls.Unmarshal(resp.TreeHeadSignature, &ds); err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, RspError{
|
||||||
|
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||||
|
StatusCode: httpRsp.StatusCode,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sth.TreeHeadSignature = ds
|
||||||
|
if err := c.VerifySTHSignature(sth); err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return &sth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySTHSignature checks the signature in sth, returning any error encountered or nil if verification is
|
||||||
|
// successful.
|
||||||
|
func (c *LogClient) VerifySTHSignature(sth ct.SignedTreeHead) error {
|
||||||
|
if c.Verifier == nil {
|
||||||
|
// Can't verify signatures without a verifier
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.Verifier.VerifySTHSignature(sth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySCTSignature checks the signature in sct for the given LogEntryType, with associated certificate chain.
|
||||||
|
func (c *LogClient) VerifySCTSignature(sct ct.SignedCertificateTimestamp, ctype ct.LogEntryType, certData []ct.ASN1Cert) error {
|
||||||
|
if c.Verifier == nil {
|
||||||
|
// Can't verify signatures without a verifier
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
leaf, err := ct.MerkleTreeLeafFromRawChain(certData, ctype, sct.Timestamp)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to build MerkleTreeLeaf: %v", err)
|
||||||
|
}
|
||||||
|
entry := ct.LogEntry{Leaf: *leaf}
|
||||||
|
return c.Verifier.VerifySCTSignature(sct, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSTHConsistency retrieves the consistency proof between two snapshots.
|
||||||
|
func (c *LogClient) GetSTHConsistency(ctx context.Context, first, second uint64) ([][]byte, error) {
|
||||||
|
base10 := 10
|
||||||
|
params := map[string]string{
|
||||||
|
"first": strconv.FormatUint(first, base10),
|
||||||
|
"second": strconv.FormatUint(second, base10),
|
||||||
|
}
|
||||||
|
var resp ct.GetSTHConsistencyResponse
|
||||||
|
httpRsp, body, err := c.GetAndParse(ctx, ct.GetSTHConsistencyPath, params, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Consistency, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProofByHash returns an audit path for the hash of an SCT.
|
||||||
|
func (c *LogClient) GetProofByHash(ctx context.Context, hash []byte, treeSize uint64) (*ct.GetProofByHashResponse, error) {
|
||||||
|
b64Hash := base64.StdEncoding.EncodeToString(hash)
|
||||||
|
base10 := 10
|
||||||
|
params := map[string]string{
|
||||||
|
"tree_size": strconv.FormatUint(treeSize, base10),
|
||||||
|
"hash": b64Hash,
|
||||||
|
}
|
||||||
|
var resp ct.GetProofByHashResponse
|
||||||
|
httpRsp, body, err := c.GetAndParse(ctx, ct.GetProofByHashPath, params, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAcceptedRoots retrieves the set of acceptable root certificates for a log.
|
||||||
|
func (c *LogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) {
|
||||||
|
var resp ct.GetRootsResponse
|
||||||
|
httpRsp, body, err := c.GetAndParse(ctx, ct.GetRootsPath, nil, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if httpRsp != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var roots []ct.ASN1Cert
|
||||||
|
for _, cert64 := range resp.Certificates {
|
||||||
|
cert, err := base64.StdEncoding.DecodeString(cert64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||||
|
}
|
||||||
|
roots = append(roots, ct.ASN1Cert{Data: cert})
|
||||||
|
}
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
221
vendor/github.com/google/certificate-transparency-go/client/multilog.go
generated
vendored
Normal file
221
vendor/github.com/google/certificate-transparency-go/client/multilog.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/golang/protobuf/ptypes"
|
||||||
|
ct "github.com/google/certificate-transparency-go"
|
||||||
|
"github.com/google/certificate-transparency-go/client/configpb"
|
||||||
|
"github.com/google/certificate-transparency-go/jsonclient"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
type interval struct {
|
||||||
|
lower *time.Time // nil => no lower bound
|
||||||
|
upper *time.Time // nil => no upper bound
|
||||||
|
}
|
||||||
|
|
||||||
|
// TemporalLogConfigFromFile creates a TemporalLogConfig object from the given
|
||||||
|
// filename, which should contain text-protobuf encoded configuration data.
|
||||||
|
func TemporalLogConfigFromFile(filename string) (*configpb.TemporalLogConfig, error) {
|
||||||
|
if len(filename) == 0 {
|
||||||
|
return nil, errors.New("log config filename empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgText, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read log config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg configpb.TemporalLogConfig
|
||||||
|
if err := proto.UnmarshalText(string(cfgText), &cfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse log config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.Shard) == 0 {
|
||||||
|
return nil, errors.New("empty log config found")
|
||||||
|
}
|
||||||
|
return &cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLogClient is an interface that allows adding certificates and pre-certificates to a log.
|
||||||
|
// Both LogClient and TemporalLogClient implement this interface, which allows users to
|
||||||
|
// commonize code for adding certs to normal/temporal logs.
|
||||||
|
type AddLogClient interface {
|
||||||
|
AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error)
|
||||||
|
AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error)
|
||||||
|
GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TemporalLogClient allows [pre-]certificates to be uploaded to a temporal log.
|
||||||
|
type TemporalLogClient struct {
|
||||||
|
Clients []*LogClient
|
||||||
|
intervals []interval
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTemporalLogClient builds a new client for interacting with a temporal log.
|
||||||
|
// The provided config should be contiguous and chronological.
|
||||||
|
func NewTemporalLogClient(cfg configpb.TemporalLogConfig, hc *http.Client) (*TemporalLogClient, error) {
|
||||||
|
if len(cfg.Shard) == 0 {
|
||||||
|
return nil, errors.New("empty config")
|
||||||
|
}
|
||||||
|
|
||||||
|
overall, err := shardInterval(cfg.Shard[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cfg.Shard[0] invalid: %v", err)
|
||||||
|
}
|
||||||
|
intervals := make([]interval, 0, len(cfg.Shard))
|
||||||
|
intervals = append(intervals, overall)
|
||||||
|
for i := 1; i < len(cfg.Shard); i++ {
|
||||||
|
interval, err := shardInterval(cfg.Shard[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cfg.Shard[%d] invalid: %v", i, err)
|
||||||
|
}
|
||||||
|
if overall.upper == nil {
|
||||||
|
return nil, fmt.Errorf("cfg.Shard[%d] extends an interval with no upper bound", i)
|
||||||
|
}
|
||||||
|
if interval.lower == nil {
|
||||||
|
return nil, fmt.Errorf("cfg.Shard[%d] has no lower bound but extends an interval", i)
|
||||||
|
}
|
||||||
|
if !interval.lower.Equal(*overall.upper) {
|
||||||
|
return nil, fmt.Errorf("cfg.Shard[%d] starts at %v but previous interval ended at %v", i, interval.lower, overall.upper)
|
||||||
|
}
|
||||||
|
overall.upper = interval.upper
|
||||||
|
intervals = append(intervals, interval)
|
||||||
|
}
|
||||||
|
clients := make([]*LogClient, 0, len(cfg.Shard))
|
||||||
|
for i, shard := range cfg.Shard {
|
||||||
|
opts := jsonclient.Options{}
|
||||||
|
opts.PublicKeyDER = shard.GetPublicKeyDer()
|
||||||
|
c, err := New(shard.Uri, hc, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create client for cfg.Shard[%d]: %v", i, err)
|
||||||
|
}
|
||||||
|
clients = append(clients, c)
|
||||||
|
}
|
||||||
|
tlc := TemporalLogClient{
|
||||||
|
Clients: clients,
|
||||||
|
intervals: intervals,
|
||||||
|
}
|
||||||
|
return &tlc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAcceptedRoots retrieves the set of acceptable root certificates for all
|
||||||
|
// of the shards of a temporal log (i.e. the union).
|
||||||
|
func (tlc *TemporalLogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) {
|
||||||
|
type result struct {
|
||||||
|
roots []ct.ASN1Cert
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
results := make(chan result, len(tlc.Clients))
|
||||||
|
for _, c := range tlc.Clients {
|
||||||
|
go func(c *LogClient) {
|
||||||
|
var r result
|
||||||
|
r.roots, r.err = c.GetAcceptedRoots(ctx)
|
||||||
|
results <- r
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
var allRoots []ct.ASN1Cert
|
||||||
|
seen := make(map[[sha256.Size]byte]bool)
|
||||||
|
for range tlc.Clients {
|
||||||
|
r := <-results
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
for _, root := range r.roots {
|
||||||
|
h := sha256.Sum256(root.Data)
|
||||||
|
if seen[h] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[h] = true
|
||||||
|
allRoots = append(allRoots, root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allRoots, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddChain adds the (DER represented) X509 chain to the appropriate log.
|
||||||
|
func (tlc *TemporalLogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
return tlc.addChain(ctx, ct.X509LogEntryType, ct.AddChainPath, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPreChain adds the (DER represented) Precertificate chain to the appropriate log.
|
||||||
|
func (tlc *TemporalLogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
return tlc.addChain(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tlc *TemporalLogClient) addChain(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||||
|
// Parse the first entry in the chain
|
||||||
|
if len(chain) == 0 {
|
||||||
|
return nil, errors.New("missing chain")
|
||||||
|
}
|
||||||
|
cert, err := x509.ParseCertificate(chain[0].Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse initial chain entry: %v", err)
|
||||||
|
}
|
||||||
|
cidx, err := tlc.IndexByDate(cert.NotAfter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find log to process cert: %v", err)
|
||||||
|
}
|
||||||
|
return tlc.Clients[cidx].addChainWithRetry(ctx, ctype, path, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexByDate returns the index of the Clients entry that is appropriate for the given
|
||||||
|
// date.
|
||||||
|
func (tlc *TemporalLogClient) IndexByDate(when time.Time) (int, error) {
|
||||||
|
for i, interval := range tlc.intervals {
|
||||||
|
if (interval.lower != nil) && when.Before(*interval.lower) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (interval.upper != nil) && !when.Before(*interval.upper) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("no log found encompassing date %v", when)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shardInterval(cfg *configpb.LogShardConfig) (interval, error) {
|
||||||
|
var interval interval
|
||||||
|
if cfg.NotAfterStart != nil {
|
||||||
|
t, err := ptypes.Timestamp(cfg.NotAfterStart)
|
||||||
|
if err != nil {
|
||||||
|
return interval, fmt.Errorf("failed to parse NotAfterStart: %v", err)
|
||||||
|
}
|
||||||
|
interval.lower = &t
|
||||||
|
}
|
||||||
|
if cfg.NotAfterLimit != nil {
|
||||||
|
t, err := ptypes.Timestamp(cfg.NotAfterLimit)
|
||||||
|
if err != nil {
|
||||||
|
return interval, fmt.Errorf("failed to parse NotAfterLimit: %v", err)
|
||||||
|
}
|
||||||
|
interval.upper = &t
|
||||||
|
}
|
||||||
|
|
||||||
|
if interval.lower != nil && interval.upper != nil && !(*interval.lower).Before(*interval.upper) {
|
||||||
|
return interval, errors.New("inverted interval")
|
||||||
|
}
|
||||||
|
return interval, nil
|
||||||
|
}
|
||||||
27
vendor/github.com/google/certificate-transparency-go/gometalinter.json
generated
vendored
Normal file
27
vendor/github.com/google/certificate-transparency-go/gometalinter.json
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"Linters": {
|
||||||
|
"license": "./scripts/check_license.sh:PATH:LINE:MESSAGE",
|
||||||
|
"forked": "./scripts/check_forked.sh:PATH:LINE:MESSAGE",
|
||||||
|
"unforked": "./scripts/check_unforked.sh:PATH:LINE:MESSAGE"
|
||||||
|
},
|
||||||
|
"Enable": [
|
||||||
|
"forked",
|
||||||
|
"gocyclo",
|
||||||
|
"gofmt",
|
||||||
|
"goimports",
|
||||||
|
"golint",
|
||||||
|
"license",
|
||||||
|
"misspell",
|
||||||
|
"unforked",
|
||||||
|
"vet"
|
||||||
|
],
|
||||||
|
"Exclude": [
|
||||||
|
"x509/",
|
||||||
|
"asn1/",
|
||||||
|
".+\\.pb\\.go",
|
||||||
|
".+\\.pb\\.gw\\.go",
|
||||||
|
"mock_.+\\.go"
|
||||||
|
],
|
||||||
|
"Cyclo": 40,
|
||||||
|
"Vendor": true
|
||||||
|
}
|
||||||
@@ -2,13 +2,16 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["logclient.go"],
|
srcs = [
|
||||||
importpath = "github.com/google/certificate-transparency/go/client",
|
"backoff.go",
|
||||||
|
"client.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/google/certificate-transparency-go/jsonclient",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/google/certificate-transparency/go:go_default_library",
|
"//vendor/github.com/google/certificate-transparency-go:go_default_library",
|
||||||
"//vendor/github.com/mreiferson/go-httpclient:go_default_library",
|
"//vendor/github.com/google/certificate-transparency-go/x509:go_default_library",
|
||||||
"//vendor/golang.org/x/net/context:go_default_library",
|
"//vendor/golang.org/x/net/context/ctxhttp:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
72
vendor/github.com/google/certificate-transparency-go/jsonclient/backoff.go
generated
vendored
Normal file
72
vendor/github.com/google/certificate-transparency-go/jsonclient/backoff.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package jsonclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type backoff struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
multiplier uint
|
||||||
|
notBefore time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// maximum backoff is 2^(maxMultiplier-1) = 128 seconds
|
||||||
|
maxMultiplier = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *backoff) set(override *time.Duration) time.Duration {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
if b.notBefore.After(time.Now()) {
|
||||||
|
if override != nil {
|
||||||
|
// If existing backoff is set but override would be longer than
|
||||||
|
// it then set it to that.
|
||||||
|
notBefore := time.Now().Add(*override)
|
||||||
|
if notBefore.After(b.notBefore) {
|
||||||
|
b.notBefore = notBefore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time.Until(b.notBefore)
|
||||||
|
}
|
||||||
|
var wait time.Duration
|
||||||
|
if override != nil {
|
||||||
|
wait = *override
|
||||||
|
} else {
|
||||||
|
if b.multiplier < maxMultiplier {
|
||||||
|
b.multiplier++
|
||||||
|
}
|
||||||
|
wait = time.Second * time.Duration(1<<(b.multiplier-1))
|
||||||
|
}
|
||||||
|
b.notBefore = time.Now().Add(wait)
|
||||||
|
return wait
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backoff) decreaseMultiplier() {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
if b.multiplier > 0 {
|
||||||
|
b.multiplier--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backoff) until() time.Time {
|
||||||
|
b.mu.RLock()
|
||||||
|
defer b.mu.RUnlock()
|
||||||
|
return b.notBefore
|
||||||
|
}
|
||||||
289
vendor/github.com/google/certificate-transparency-go/jsonclient/client.go
generated
vendored
Normal file
289
vendor/github.com/google/certificate-transparency-go/jsonclient/client.go
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package jsonclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ct "github.com/google/certificate-transparency-go"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
"golang.org/x/net/context/ctxhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxJitter = 250 * time.Millisecond
|
||||||
|
|
||||||
|
type backoffer interface {
|
||||||
|
// set adjusts/increases the current backoff interval (typically on retryable failure);
|
||||||
|
// if the optional parameter is provided, this will be used as the interval if it is greater
|
||||||
|
// than the currently set interval. Returns the current wait period so that it can be
|
||||||
|
// logged along with any error message.
|
||||||
|
set(*time.Duration) time.Duration
|
||||||
|
// decreaseMultiplier reduces the current backoff multiplier, typically on success.
|
||||||
|
decreaseMultiplier()
|
||||||
|
// until returns the time until which the client should wait before making a request,
|
||||||
|
// it may be in the past in which case it should be ignored.
|
||||||
|
until() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONClient provides common functionality for interacting with a JSON server
|
||||||
|
// that uses cryptographic signatures.
|
||||||
|
type JSONClient struct {
|
||||||
|
uri string // the base URI of the server. e.g. http://ct.googleapis/pilot
|
||||||
|
httpClient *http.Client // used to interact with the server via HTTP
|
||||||
|
Verifier *ct.SignatureVerifier // nil for no verification (e.g. no public key available)
|
||||||
|
logger Logger // interface to use for logging warnings and errors
|
||||||
|
backoff backoffer // object used to store and calculate backoff information
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger is a simple logging interface used to log internal errors and warnings
|
||||||
|
type Logger interface {
|
||||||
|
// Printf formats and logs a message
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options are the options for creating a new JSONClient.
|
||||||
|
type Options struct {
|
||||||
|
// Interface to use for logging warnings and errors, if nil the
|
||||||
|
// standard library log package will be used.
|
||||||
|
Logger Logger
|
||||||
|
// PEM format public key to use for signature verification.
|
||||||
|
PublicKey string
|
||||||
|
// DER format public key to use for signature verification.
|
||||||
|
PublicKeyDER []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePublicKey parses and returns the public key contained in opts.
|
||||||
|
// If both opts.PublicKey and opts.PublicKeyDER are set, PublicKeyDER is used.
|
||||||
|
// If neither is set, nil will be returned.
|
||||||
|
func (opts *Options) ParsePublicKey() (crypto.PublicKey, error) {
|
||||||
|
if len(opts.PublicKeyDER) > 0 {
|
||||||
|
return x509.ParsePKIXPublicKey(opts.PublicKeyDER)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.PublicKey != "" {
|
||||||
|
pubkey, _ /* keyhash */, rest, err := ct.PublicKeyFromPEM([]byte(opts.PublicKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(rest) > 0 {
|
||||||
|
return nil, errors.New("extra data found after PEM key decoded")
|
||||||
|
}
|
||||||
|
return pubkey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type basicLogger struct{}
|
||||||
|
|
||||||
|
func (bl *basicLogger) Printf(msg string, args ...interface{}) {
|
||||||
|
log.Printf(msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New constructs a new JSONClient instance, for the given base URI, using the
|
||||||
|
// given http.Client object (if provided) and the Options object.
|
||||||
|
// If opts does not specify a public key, signatures will not be verified.
|
||||||
|
func New(uri string, hc *http.Client, opts Options) (*JSONClient, error) {
|
||||||
|
pubkey, err := opts.ParsePublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid public key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var verifier *ct.SignatureVerifier
|
||||||
|
if pubkey != nil {
|
||||||
|
var err error
|
||||||
|
verifier, err = ct.NewSignatureVerifier(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hc == nil {
|
||||||
|
hc = new(http.Client)
|
||||||
|
}
|
||||||
|
logger := opts.Logger
|
||||||
|
if logger == nil {
|
||||||
|
logger = &basicLogger{}
|
||||||
|
}
|
||||||
|
return &JSONClient{
|
||||||
|
uri: strings.TrimRight(uri, "/"),
|
||||||
|
httpClient: hc,
|
||||||
|
Verifier: verifier,
|
||||||
|
logger: logger,
|
||||||
|
backoff: &backoff{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAndParse makes a HTTP GET call to the given path, and attempta to parse
|
||||||
|
// the response as a JSON representation of the rsp structure. Returns the
|
||||||
|
// http.Response, the body of the response, and an error. Note that the
|
||||||
|
// returned http.Response can be non-nil even when an error is returned,
|
||||||
|
// in particular when the HTTP status is not OK or when the JSON parsing fails.
|
||||||
|
func (c *JSONClient) GetAndParse(ctx context.Context, path string, params map[string]string, rsp interface{}) (*http.Response, []byte, error) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, nil, errors.New("context.Context required")
|
||||||
|
}
|
||||||
|
// Build a GET request with URL-encoded parameters.
|
||||||
|
vals := url.Values{}
|
||||||
|
for k, v := range params {
|
||||||
|
vals.Add(k, v)
|
||||||
|
}
|
||||||
|
fullURI := fmt.Sprintf("%s%s?%s", c.uri, path, vals.Encode())
|
||||||
|
httpReq, err := http.NewRequest(http.MethodGet, fullURI, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRsp, err := ctxhttp.Do(ctx, c.httpClient, httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read everything now so http.Client can reuse the connection.
|
||||||
|
body, err := ioutil.ReadAll(httpRsp.Body)
|
||||||
|
httpRsp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return httpRsp, body, fmt.Errorf("failed to read response body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpRsp.StatusCode != http.StatusOK {
|
||||||
|
return httpRsp, body, fmt.Errorf("got HTTP Status %q", httpRsp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(bytes.NewReader(body)).Decode(rsp); err != nil {
|
||||||
|
return httpRsp, body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpRsp, body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostAndParse makes a HTTP POST call to the given path, including the request
|
||||||
|
// parameters, and attempts to parse the response as a JSON representation of
|
||||||
|
// the rsp structure. Returns the http.Response, the body of the response, and
|
||||||
|
// an error. Note that the returned http.Response can be non-nil even when an
|
||||||
|
// error is returned, in particular when the HTTP status is not OK or when the
|
||||||
|
// JSON parsing fails.
|
||||||
|
func (c *JSONClient) PostAndParse(ctx context.Context, path string, req, rsp interface{}) (*http.Response, []byte, error) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, nil, errors.New("context.Context required")
|
||||||
|
}
|
||||||
|
// Build a POST request with JSON body.
|
||||||
|
postBody, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
fullURI := fmt.Sprintf("%s%s", c.uri, path)
|
||||||
|
httpReq, err := http.NewRequest(http.MethodPost, fullURI, bytes.NewReader(postBody))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
httpRsp, err := ctxhttp.Do(ctx, c.httpClient, httpReq)
|
||||||
|
|
||||||
|
// Read all of the body, if there is one, so that the http.Client can do Keep-Alive.
|
||||||
|
var body []byte
|
||||||
|
if httpRsp != nil {
|
||||||
|
body, err = ioutil.ReadAll(httpRsp.Body)
|
||||||
|
httpRsp.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return httpRsp, body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpRsp.StatusCode == http.StatusOK {
|
||||||
|
if err = json.Unmarshal(body, &rsp); err != nil {
|
||||||
|
return httpRsp, body, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpRsp, body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForBackoff blocks until the defined backoff interval or context has expired, if the returned
|
||||||
|
// not before time is in the past it returns immediately.
|
||||||
|
func (c *JSONClient) waitForBackoff(ctx context.Context) error {
|
||||||
|
dur := time.Until(c.backoff.until().Add(time.Millisecond * time.Duration(rand.Intn(int(maxJitter.Seconds()*1000)))))
|
||||||
|
if dur < 0 {
|
||||||
|
dur = 0
|
||||||
|
}
|
||||||
|
backoffTimer := time.NewTimer(dur)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-backoffTimer.C:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostAndParseWithRetry makes a HTTP POST call, but retries (with backoff) on
|
||||||
|
// retriable errors; the caller should set a deadline on the provided context
|
||||||
|
// to prevent infinite retries. Return values are as for PostAndParse.
|
||||||
|
func (c *JSONClient) PostAndParseWithRetry(ctx context.Context, path string, req, rsp interface{}) (*http.Response, []byte, error) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, nil, errors.New("context.Context required")
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
httpRsp, body, err := c.PostAndParse(ctx, path, req, rsp)
|
||||||
|
if err != nil {
|
||||||
|
// Don't retry context errors.
|
||||||
|
if err == context.Canceled || err == context.DeadlineExceeded {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
wait := c.backoff.set(nil)
|
||||||
|
c.logger.Printf("Request failed, backing-off for %s: %s", wait, err)
|
||||||
|
} else {
|
||||||
|
switch {
|
||||||
|
case httpRsp.StatusCode == http.StatusOK:
|
||||||
|
return httpRsp, body, nil
|
||||||
|
case httpRsp.StatusCode == http.StatusRequestTimeout:
|
||||||
|
// Request timeout, retry immediately
|
||||||
|
c.logger.Printf("Request timed out, retrying immediately")
|
||||||
|
case httpRsp.StatusCode == http.StatusServiceUnavailable:
|
||||||
|
var backoff *time.Duration
|
||||||
|
// Retry-After may be either a number of seconds as a int or a RFC 1123
|
||||||
|
// date string (RFC 7231 Section 7.1.3)
|
||||||
|
if retryAfter := httpRsp.Header.Get("Retry-After"); retryAfter != "" {
|
||||||
|
if seconds, err := strconv.Atoi(retryAfter); err == nil {
|
||||||
|
b := time.Duration(seconds) * time.Second
|
||||||
|
backoff = &b
|
||||||
|
} else if date, err := time.Parse(time.RFC1123, retryAfter); err == nil {
|
||||||
|
b := date.Sub(time.Now())
|
||||||
|
backoff = &b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wait := c.backoff.set(backoff)
|
||||||
|
c.logger.Printf("Request failed, backing-off for %s: got HTTP status %s", wait, httpRsp.Status)
|
||||||
|
default:
|
||||||
|
return httpRsp, body, fmt.Errorf("got HTTP Status %q", httpRsp.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.waitForBackoff(ctx); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
255
vendor/github.com/google/certificate-transparency-go/serialization.go
generated
vendored
Normal file
255
vendor/github.com/google/certificate-transparency-go/serialization.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ct
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/tls"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SerializeSCTSignatureInput serializes the passed in sct and log entry into
|
||||||
|
// the correct format for signing.
|
||||||
|
func SerializeSCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) {
|
||||||
|
switch sct.SCTVersion {
|
||||||
|
case V1:
|
||||||
|
input := CertificateTimestamp{
|
||||||
|
SCTVersion: sct.SCTVersion,
|
||||||
|
SignatureType: CertificateTimestampSignatureType,
|
||||||
|
Timestamp: sct.Timestamp,
|
||||||
|
EntryType: entry.Leaf.TimestampedEntry.EntryType,
|
||||||
|
Extensions: sct.Extensions,
|
||||||
|
}
|
||||||
|
switch entry.Leaf.TimestampedEntry.EntryType {
|
||||||
|
case X509LogEntryType:
|
||||||
|
input.X509Entry = entry.Leaf.TimestampedEntry.X509Entry
|
||||||
|
case PrecertLogEntryType:
|
||||||
|
input.PrecertEntry = &PreCert{
|
||||||
|
IssuerKeyHash: entry.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash,
|
||||||
|
TBSCertificate: entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate,
|
||||||
|
}
|
||||||
|
case XJSONLogEntryType:
|
||||||
|
input.JSONEntry = entry.Leaf.TimestampedEntry.JSONEntry
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported entry type %s", entry.Leaf.TimestampedEntry.EntryType)
|
||||||
|
}
|
||||||
|
return tls.Marshal(input)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeSTHSignatureInput serializes the passed in STH into the correct
|
||||||
|
// format for signing.
|
||||||
|
func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) {
|
||||||
|
switch sth.Version {
|
||||||
|
case V1:
|
||||||
|
if len(sth.SHA256RootHash) != crypto.SHA256.Size() {
|
||||||
|
return nil, fmt.Errorf("invalid TreeHash length, got %d expected %d", len(sth.SHA256RootHash), crypto.SHA256.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
input := TreeHeadSignature{
|
||||||
|
Version: sth.Version,
|
||||||
|
SignatureType: TreeHashSignatureType,
|
||||||
|
Timestamp: sth.Timestamp,
|
||||||
|
TreeSize: sth.TreeSize,
|
||||||
|
SHA256RootHash: sth.SHA256RootHash,
|
||||||
|
}
|
||||||
|
return tls.Marshal(input)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported STH version %d", sth.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateX509MerkleTreeLeaf generates a MerkleTreeLeaf for an X509 cert
|
||||||
|
func CreateX509MerkleTreeLeaf(cert ASN1Cert, timestamp uint64) *MerkleTreeLeaf {
|
||||||
|
return &MerkleTreeLeaf{
|
||||||
|
Version: V1,
|
||||||
|
LeafType: TimestampedEntryLeafType,
|
||||||
|
TimestampedEntry: &TimestampedEntry{
|
||||||
|
Timestamp: timestamp,
|
||||||
|
EntryType: X509LogEntryType,
|
||||||
|
X509Entry: &cert,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateJSONMerkleTreeLeaf creates the merkle tree leaf for json data.
|
||||||
|
func CreateJSONMerkleTreeLeaf(data interface{}, timestamp uint64) *MerkleTreeLeaf {
|
||||||
|
jsonData, err := json.Marshal(AddJSONRequest{Data: data})
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Match the JSON serialization implemented by json-c
|
||||||
|
jsonStr := strings.Replace(string(jsonData), ":", ": ", -1)
|
||||||
|
jsonStr = strings.Replace(jsonStr, ",", ", ", -1)
|
||||||
|
jsonStr = strings.Replace(jsonStr, "{", "{ ", -1)
|
||||||
|
jsonStr = strings.Replace(jsonStr, "}", " }", -1)
|
||||||
|
jsonStr = strings.Replace(jsonStr, "/", `\/`, -1)
|
||||||
|
// TODO: Pending google/certificate-transparency#1243, replace with
|
||||||
|
// ObjectHash once supported by CT server.
|
||||||
|
|
||||||
|
return &MerkleTreeLeaf{
|
||||||
|
Version: V1,
|
||||||
|
LeafType: TimestampedEntryLeafType,
|
||||||
|
TimestampedEntry: &TimestampedEntry{
|
||||||
|
Timestamp: timestamp,
|
||||||
|
EntryType: XJSONLogEntryType,
|
||||||
|
JSONEntry: &JSONDataEntry{Data: []byte(jsonStr)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MerkleTreeLeafFromRawChain generates a MerkleTreeLeaf from a chain (in DER-encoded form) and timestamp.
|
||||||
|
func MerkleTreeLeafFromRawChain(rawChain []ASN1Cert, etype LogEntryType, timestamp uint64) (*MerkleTreeLeaf, error) {
|
||||||
|
// Need at most 3 of the chain
|
||||||
|
count := 3
|
||||||
|
if count > len(rawChain) {
|
||||||
|
count = len(rawChain)
|
||||||
|
}
|
||||||
|
chain := make([]*x509.Certificate, count)
|
||||||
|
for i := range chain {
|
||||||
|
cert, err := x509.ParseCertificate(rawChain[i].Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse chain[%d] cert: %v", i, err)
|
||||||
|
}
|
||||||
|
chain[i] = cert
|
||||||
|
}
|
||||||
|
return MerkleTreeLeafFromChain(chain, etype, timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MerkleTreeLeafFromChain generates a MerkleTreeLeaf from a chain and timestamp.
|
||||||
|
func MerkleTreeLeafFromChain(chain []*x509.Certificate, etype LogEntryType, timestamp uint64) (*MerkleTreeLeaf, error) {
|
||||||
|
leaf := MerkleTreeLeaf{
|
||||||
|
Version: V1,
|
||||||
|
LeafType: TimestampedEntryLeafType,
|
||||||
|
TimestampedEntry: &TimestampedEntry{
|
||||||
|
EntryType: etype,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if etype == X509LogEntryType {
|
||||||
|
leaf.TimestampedEntry.X509Entry = &ASN1Cert{Data: chain[0].Raw}
|
||||||
|
return &leaf, nil
|
||||||
|
}
|
||||||
|
if etype != PrecertLogEntryType {
|
||||||
|
return nil, fmt.Errorf("unknown LogEntryType %d", etype)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-certs are more complicated. First, parse the leaf pre-cert and its
|
||||||
|
// putative issuer.
|
||||||
|
if len(chain) < 2 {
|
||||||
|
return nil, fmt.Errorf("no issuer cert available for precert leaf building")
|
||||||
|
}
|
||||||
|
issuer := chain[1]
|
||||||
|
cert := chain[0]
|
||||||
|
|
||||||
|
var preIssuer *x509.Certificate
|
||||||
|
if IsPreIssuer(issuer) {
|
||||||
|
// Replace the cert's issuance information with details from the pre-issuer.
|
||||||
|
preIssuer = issuer
|
||||||
|
|
||||||
|
// The issuer of the pre-cert is not going to be the issuer of the final
|
||||||
|
// cert. Change to use the final issuer's key hash.
|
||||||
|
if len(chain) < 3 {
|
||||||
|
return nil, fmt.Errorf("no issuer cert available for pre-issuer")
|
||||||
|
}
|
||||||
|
issuer = chain[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, post-process the DER-encoded TBSCertificate, to remove the CT poison
|
||||||
|
// extension and possibly update the issuer field.
|
||||||
|
defangedTBS, err := x509.BuildPrecertTBS(cert.RawTBSCertificate, preIssuer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to remove poison extension: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf.TimestampedEntry.EntryType = PrecertLogEntryType
|
||||||
|
leaf.TimestampedEntry.PrecertEntry = &PreCert{
|
||||||
|
IssuerKeyHash: sha256.Sum256(issuer.RawSubjectPublicKeyInfo),
|
||||||
|
TBSCertificate: defangedTBS,
|
||||||
|
}
|
||||||
|
return &leaf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPreIssuer indicates whether a certificate is a pre-cert issuer with the specific
|
||||||
|
// certificate transparency extended key usage.
|
||||||
|
func IsPreIssuer(issuer *x509.Certificate) bool {
|
||||||
|
for _, eku := range issuer.ExtKeyUsage {
|
||||||
|
if eku == x509.ExtKeyUsageCertificateTransparency {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data after JSON parsing)
|
||||||
|
// into a LogEntry object (which includes x509.Certificate objects, after TLS and ASN.1 parsing).
|
||||||
|
// Note that this function may return a valid LogEntry object and a non-nil error value, when
|
||||||
|
// the error indicates a non-fatal parsing error (of type x509.NonFatalErrors).
|
||||||
|
func LogEntryFromLeaf(index int64, leafEntry *LeafEntry) (*LogEntry, error) {
|
||||||
|
var leaf MerkleTreeLeaf
|
||||||
|
if rest, err := tls.Unmarshal(leafEntry.LeafInput, &leaf); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal MerkleTreeLeaf for index %d: %v", index, err)
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, fmt.Errorf("trailing data (%d bytes) after MerkleTreeLeaf for index %d", len(rest), index)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
entry := LogEntry{Index: index, Leaf: leaf}
|
||||||
|
switch leaf.TimestampedEntry.EntryType {
|
||||||
|
case X509LogEntryType:
|
||||||
|
var certChain CertificateChain
|
||||||
|
if rest, err := tls.Unmarshal(leafEntry.ExtraData, &certChain); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal ExtraData for index %d: %v", index, err)
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, fmt.Errorf("trailing data (%d bytes) after CertificateChain for index %d", len(rest), index)
|
||||||
|
}
|
||||||
|
entry.Chain = certChain.Entries
|
||||||
|
entry.X509Cert, err = leaf.X509Certificate()
|
||||||
|
if _, ok := err.(x509.NonFatalErrors); !ok && err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse certificate in MerkleTreeLeaf for index %d: %v", index, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case PrecertLogEntryType:
|
||||||
|
var precertChain PrecertChainEntry
|
||||||
|
if rest, err := tls.Unmarshal(leafEntry.ExtraData, &precertChain); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal PrecertChainEntry for index %d: %v", index, err)
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return nil, fmt.Errorf("trailing data (%d bytes) after PrecertChainEntry for index %d", len(rest), index)
|
||||||
|
}
|
||||||
|
entry.Chain = precertChain.CertificateChain
|
||||||
|
var tbsCert *x509.Certificate
|
||||||
|
tbsCert, err = leaf.Precertificate()
|
||||||
|
if _, ok := err.(x509.NonFatalErrors); !ok && err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse precertificate in MerkleTreeLeaf for index %d: %v", index, err)
|
||||||
|
}
|
||||||
|
entry.Precert = &Precertificate{
|
||||||
|
Submitted: precertChain.PreCertificate,
|
||||||
|
IssuerKeyHash: leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash,
|
||||||
|
TBSCertificate: tbsCert,
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("saw unknown entry type at index %d: %v", index, leaf.TimestampedEntry.EntryType)
|
||||||
|
}
|
||||||
|
// err may hold a x509.NonFatalErrors object.
|
||||||
|
return &entry, err
|
||||||
|
}
|
||||||
@@ -1,3 +1,17 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package ct
|
package ct
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,14 +20,13 @@ import (
|
|||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/asn1"
|
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
|
||||||
|
"github.com/google/certificate-transparency-go/tls"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
)
|
)
|
||||||
|
|
||||||
var allowVerificationWithNonCompliantKeys = flag.Bool("allow_verification_with_non_compliant_keys", false,
|
var allowVerificationWithNonCompliantKeys = flag.Bool("allow_verification_with_non_compliant_keys", false,
|
||||||
@@ -64,61 +77,18 @@ func NewSignatureVerifier(pk crypto.PublicKey) (*SignatureVerifier, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifySignature verifies that the passed in signature over data was created by our PublicKey.
|
// VerifySignature verifies the given signature sig matches the data.
|
||||||
// Currently, only SHA256 is supported as a HashAlgorithm, and only ECDSA and RSA signatures are supported.
|
func (s SignatureVerifier) VerifySignature(data []byte, sig tls.DigitallySigned) error {
|
||||||
func (s SignatureVerifier) verifySignature(data []byte, sig DigitallySigned) error {
|
return tls.VerifySignature(s.pubKey, data, sig)
|
||||||
if sig.HashAlgorithm != SHA256 {
|
|
||||||
return fmt.Errorf("unsupported HashAlgorithm in signature: %v", sig.HashAlgorithm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasherType := crypto.SHA256
|
// VerifySCTSignature verifies that the SCT's signature is valid for the given LogEntry.
|
||||||
hasher := hasherType.New()
|
|
||||||
if _, err := hasher.Write(data); err != nil {
|
|
||||||
return fmt.Errorf("failed to write to hasher: %v", err)
|
|
||||||
}
|
|
||||||
hash := hasher.Sum([]byte{})
|
|
||||||
|
|
||||||
switch sig.SignatureAlgorithm {
|
|
||||||
case RSA:
|
|
||||||
rsaKey, ok := s.pubKey.(*rsa.PublicKey)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("cannot verify RSA signature with %T key", s.pubKey)
|
|
||||||
}
|
|
||||||
if err := rsa.VerifyPKCS1v15(rsaKey, hasherType, hash, sig.Signature); err != nil {
|
|
||||||
return fmt.Errorf("failed to verify rsa signature: %v", err)
|
|
||||||
}
|
|
||||||
case ECDSA:
|
|
||||||
ecdsaKey, ok := s.pubKey.(*ecdsa.PublicKey)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("cannot verify ECDSA signature with %T key", s.pubKey)
|
|
||||||
}
|
|
||||||
var ecdsaSig struct {
|
|
||||||
R, S *big.Int
|
|
||||||
}
|
|
||||||
rest, err := asn1.Unmarshal(sig.Signature, &ecdsaSig)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal ECDSA signature: %v", err)
|
|
||||||
}
|
|
||||||
if len(rest) != 0 {
|
|
||||||
log.Printf("Garbage following signature %v", rest)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ecdsa.Verify(ecdsaKey, hash, ecdsaSig.R, ecdsaSig.S) {
|
|
||||||
return errors.New("failed to verify ecdsa signature")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported signature type %v", sig.SignatureAlgorithm)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifySCTSignature verifies that the SCT's signature is valid for the given LogEntry
|
|
||||||
func (s SignatureVerifier) VerifySCTSignature(sct SignedCertificateTimestamp, entry LogEntry) error {
|
func (s SignatureVerifier) VerifySCTSignature(sct SignedCertificateTimestamp, entry LogEntry) error {
|
||||||
sctData, err := SerializeSCTSignatureInput(sct, entry)
|
sctData, err := SerializeSCTSignatureInput(sct, entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.verifySignature(sctData, sct.Signature)
|
return s.VerifySignature(sctData, tls.DigitallySigned(sct.Signature))
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySTHSignature verifies that the STH's signature is valid.
|
// VerifySTHSignature verifies that the STH's signature is valid.
|
||||||
@@ -127,5 +97,5 @@ func (s SignatureVerifier) VerifySTHSignature(sth SignedTreeHead) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.verifySignature(sthData, sth.TreeHeadSignature)
|
return s.VerifySignature(sthData, tls.DigitallySigned(sth.TreeHeadSignature))
|
||||||
}
|
}
|
||||||
27
vendor/github.com/google/certificate-transparency-go/tls/BUILD
generated
vendored
Normal file
27
vendor/github.com/google/certificate-transparency-go/tls/BUILD
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"signature.go",
|
||||||
|
"tls.go",
|
||||||
|
"types.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/google/certificate-transparency-go/tls",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = ["//vendor/github.com/google/certificate-transparency-go/asn1:go_default_library"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
152
vendor/github.com/google/certificate-transparency-go/tls/signature.go
generated
vendored
Normal file
152
vendor/github.com/google/certificate-transparency-go/tls/signature.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/dsa"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
_ "crypto/md5" // For registration side-effect
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
_ "crypto/sha1" // For registration side-effect
|
||||||
|
_ "crypto/sha256" // For registration side-effect
|
||||||
|
_ "crypto/sha512" // For registration side-effect
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dsaSig struct {
|
||||||
|
R, S *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateHash(algo HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) {
|
||||||
|
var hashType crypto.Hash
|
||||||
|
switch algo {
|
||||||
|
case MD5:
|
||||||
|
hashType = crypto.MD5
|
||||||
|
case SHA1:
|
||||||
|
hashType = crypto.SHA1
|
||||||
|
case SHA224:
|
||||||
|
hashType = crypto.SHA224
|
||||||
|
case SHA256:
|
||||||
|
hashType = crypto.SHA256
|
||||||
|
case SHA384:
|
||||||
|
hashType = crypto.SHA384
|
||||||
|
case SHA512:
|
||||||
|
hashType = crypto.SHA512
|
||||||
|
default:
|
||||||
|
return nil, hashType, fmt.Errorf("unsupported Algorithm.Hash in signature: %v", algo)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher := hashType.New()
|
||||||
|
if _, err := hasher.Write(data); err != nil {
|
||||||
|
return nil, hashType, fmt.Errorf("failed to write to hasher: %v", err)
|
||||||
|
}
|
||||||
|
return hasher.Sum([]byte{}), hashType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySignature verifies that the passed in signature over data was created by the given PublicKey.
|
||||||
|
func VerifySignature(pubKey crypto.PublicKey, data []byte, sig DigitallySigned) error {
|
||||||
|
hash, hashType, err := generateHash(sig.Algorithm.Hash, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sig.Algorithm.Signature {
|
||||||
|
case RSA:
|
||||||
|
rsaKey, ok := pubKey.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("cannot verify RSA signature with %T key", pubKey)
|
||||||
|
}
|
||||||
|
if err := rsa.VerifyPKCS1v15(rsaKey, hashType, hash, sig.Signature); err != nil {
|
||||||
|
return fmt.Errorf("failed to verify rsa signature: %v", err)
|
||||||
|
}
|
||||||
|
case DSA:
|
||||||
|
dsaKey, ok := pubKey.(*dsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("cannot verify DSA signature with %T key", pubKey)
|
||||||
|
}
|
||||||
|
var dsaSig dsaSig
|
||||||
|
rest, err := asn1.Unmarshal(sig.Signature, &dsaSig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal DSA signature: %v", err)
|
||||||
|
}
|
||||||
|
if len(rest) != 0 {
|
||||||
|
log.Printf("Garbage following signature %v", rest)
|
||||||
|
}
|
||||||
|
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
|
||||||
|
return errors.New("DSA signature contained zero or negative values")
|
||||||
|
}
|
||||||
|
if !dsa.Verify(dsaKey, hash, dsaSig.R, dsaSig.S) {
|
||||||
|
return errors.New("failed to verify DSA signature")
|
||||||
|
}
|
||||||
|
case ECDSA:
|
||||||
|
ecdsaKey, ok := pubKey.(*ecdsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("cannot verify ECDSA signature with %T key", pubKey)
|
||||||
|
}
|
||||||
|
var ecdsaSig dsaSig
|
||||||
|
rest, err := asn1.Unmarshal(sig.Signature, &ecdsaSig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal ECDSA signature: %v", err)
|
||||||
|
}
|
||||||
|
if len(rest) != 0 {
|
||||||
|
log.Printf("Garbage following signature %v", rest)
|
||||||
|
}
|
||||||
|
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
|
||||||
|
return errors.New("ECDSA signature contained zero or negative values")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ecdsa.Verify(ecdsaKey, hash, ecdsaSig.R, ecdsaSig.S) {
|
||||||
|
return errors.New("failed to verify ECDSA signature")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported Algorithm.Signature in signature: %v", sig.Algorithm.Hash)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSignature builds a signature over the given data using the specified hash algorithm and private key.
|
||||||
|
func CreateSignature(privKey crypto.PrivateKey, hashAlgo HashAlgorithm, data []byte) (DigitallySigned, error) {
|
||||||
|
var sig DigitallySigned
|
||||||
|
sig.Algorithm.Hash = hashAlgo
|
||||||
|
hash, hashType, err := generateHash(sig.Algorithm.Hash, data)
|
||||||
|
if err != nil {
|
||||||
|
return sig, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch privKey := privKey.(type) {
|
||||||
|
case rsa.PrivateKey:
|
||||||
|
sig.Algorithm.Signature = RSA
|
||||||
|
sig.Signature, err = rsa.SignPKCS1v15(rand.Reader, &privKey, hashType, hash)
|
||||||
|
return sig, err
|
||||||
|
case ecdsa.PrivateKey:
|
||||||
|
sig.Algorithm.Signature = ECDSA
|
||||||
|
var ecdsaSig dsaSig
|
||||||
|
ecdsaSig.R, ecdsaSig.S, err = ecdsa.Sign(rand.Reader, &privKey, hash)
|
||||||
|
if err != nil {
|
||||||
|
return sig, err
|
||||||
|
}
|
||||||
|
sig.Signature, err = asn1.Marshal(ecdsaSig)
|
||||||
|
return sig, err
|
||||||
|
default:
|
||||||
|
return sig, fmt.Errorf("unsupported private key type %T", privKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
711
vendor/github.com/google/certificate-transparency-go/tls/tls.go
generated
vendored
Normal file
711
vendor/github.com/google/certificate-transparency-go/tls/tls.go
generated
vendored
Normal file
@@ -0,0 +1,711 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package tls implements functionality for dealing with TLS-encoded data,
|
||||||
|
// as defined in RFC 5246. This includes parsing and generation of TLS-encoded
|
||||||
|
// data, together with utility functions for dealing with the DigitallySigned
|
||||||
|
// TLS type.
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file holds utility functions for TLS encoding/decoding data
|
||||||
|
// as per RFC 5246 section 4.
|
||||||
|
|
||||||
|
// A structuralError suggests that the TLS data is valid, but the Go type
|
||||||
|
// which is receiving it doesn't match.
|
||||||
|
type structuralError struct {
|
||||||
|
field string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e structuralError) Error() string {
|
||||||
|
var prefix string
|
||||||
|
if e.field != "" {
|
||||||
|
prefix = e.field + ": "
|
||||||
|
}
|
||||||
|
return "tls: structure error: " + prefix + e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// A syntaxError suggests that the TLS data is invalid.
|
||||||
|
type syntaxError struct {
|
||||||
|
field string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e syntaxError) Error() string {
|
||||||
|
var prefix string
|
||||||
|
if e.field != "" {
|
||||||
|
prefix = e.field + ": "
|
||||||
|
}
|
||||||
|
return "tls: syntax error: " + prefix + e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint24 is an unsigned 3-byte integer.
|
||||||
|
type Uint24 uint32
|
||||||
|
|
||||||
|
// Enum is an unsigned integer.
|
||||||
|
type Enum uint64
|
||||||
|
|
||||||
|
var (
|
||||||
|
uint8Type = reflect.TypeOf(uint8(0))
|
||||||
|
uint16Type = reflect.TypeOf(uint16(0))
|
||||||
|
uint24Type = reflect.TypeOf(Uint24(0))
|
||||||
|
uint32Type = reflect.TypeOf(uint32(0))
|
||||||
|
uint64Type = reflect.TypeOf(uint64(0))
|
||||||
|
enumType = reflect.TypeOf(Enum(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unmarshal parses the TLS-encoded data in b and uses the reflect package to
|
||||||
|
// fill in an arbitrary value pointed at by val. Because Unmarshal uses the
|
||||||
|
// reflect package, the structs being written to must use exported fields
|
||||||
|
// (upper case names).
|
||||||
|
//
|
||||||
|
// The mappings between TLS types and Go types is as follows; some fields
|
||||||
|
// must have tags (to indicate their encoded size).
|
||||||
|
//
|
||||||
|
// TLS Go Required Tags
|
||||||
|
// opaque byte / uint8
|
||||||
|
// uint8 byte / uint8
|
||||||
|
// uint16 uint16
|
||||||
|
// uint24 tls.Uint24
|
||||||
|
// uint32 uint32
|
||||||
|
// uint64 uint64
|
||||||
|
// enum tls.Enum size:S or maxval:N
|
||||||
|
// Type<N,M> []Type minlen:N,maxlen:M
|
||||||
|
// opaque[N] [N]byte / [N]uint8
|
||||||
|
// uint8[N] [N]byte / [N]uint8
|
||||||
|
// struct { } struct { }
|
||||||
|
// select(T) {
|
||||||
|
// case e1: Type *T selector:Field,val:e1
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// TLS variants (RFC 5246 s4.6.1) are only supported when the value of the
|
||||||
|
// associated enumeration type is available earlier in the same enclosing
|
||||||
|
// struct, and each possible variant is marked with a selector tag (to
|
||||||
|
// indicate which field selects the variants) and a val tag (to indicate
|
||||||
|
// what value of the selector picks this particular field).
|
||||||
|
//
|
||||||
|
// For example, a TLS structure:
|
||||||
|
//
|
||||||
|
// enum { e1(1), e2(2) } EnumType;
|
||||||
|
// struct {
|
||||||
|
// EnumType sel;
|
||||||
|
// select(sel) {
|
||||||
|
// case e1: uint16
|
||||||
|
// case e2: uint32
|
||||||
|
// } data;
|
||||||
|
// } VariantItem;
|
||||||
|
//
|
||||||
|
// would have a corresponding Go type:
|
||||||
|
//
|
||||||
|
// type VariantItem struct {
|
||||||
|
// Sel tls.Enum `tls:"maxval:2"`
|
||||||
|
// Data16 *uint16 `tls:"selector:Sel,val:1"`
|
||||||
|
// Data32 *uint32 `tls:"selector:Sel,val:2"`
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// TLS fixed-length vectors of types other than opaque or uint8 are not supported.
|
||||||
|
//
|
||||||
|
// For TLS variable-length vectors that are themselves used in other vectors,
|
||||||
|
// create a single-field structure to represent the inner type. For example, for:
|
||||||
|
//
|
||||||
|
// opaque InnerType<1..65535>;
|
||||||
|
// struct {
|
||||||
|
// InnerType inners<1,65535>;
|
||||||
|
// } Something;
|
||||||
|
//
|
||||||
|
// convert to:
|
||||||
|
//
|
||||||
|
// type InnerType struct {
|
||||||
|
// Val []byte `tls:"minlen:1,maxlen:65535"`
|
||||||
|
// }
|
||||||
|
// type Something struct {
|
||||||
|
// Inners []InnerType `tls:"minlen:1,maxlen:65535"`
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the encoded value does not fit in the Go type, Unmarshal returns a parse error.
|
||||||
|
func Unmarshal(b []byte, val interface{}) ([]byte, error) {
|
||||||
|
return UnmarshalWithParams(b, val, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalWithParams allows field parameters to be specified for the
|
||||||
|
// top-level element. The form of the params is the same as the field tags.
|
||||||
|
func UnmarshalWithParams(b []byte, val interface{}, params string) ([]byte, error) {
|
||||||
|
info, err := fieldTagToFieldInfo(params, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// The passed in interface{} is a pointer (to allow the value to be written
|
||||||
|
// to); extract the pointed-to object as a reflect.Value, so parseField
|
||||||
|
// can do various introspection things.
|
||||||
|
v := reflect.ValueOf(val).Elem()
|
||||||
|
offset, err := parseField(v, b, 0, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[offset:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the number of bytes needed to encode values up to (and including) x.
|
||||||
|
func byteCount(x uint64) uint {
|
||||||
|
switch {
|
||||||
|
case x < 0x100:
|
||||||
|
return 1
|
||||||
|
case x < 0x10000:
|
||||||
|
return 2
|
||||||
|
case x < 0x1000000:
|
||||||
|
return 3
|
||||||
|
case x < 0x100000000:
|
||||||
|
return 4
|
||||||
|
case x < 0x10000000000:
|
||||||
|
return 5
|
||||||
|
case x < 0x1000000000000:
|
||||||
|
return 6
|
||||||
|
case x < 0x100000000000000:
|
||||||
|
return 7
|
||||||
|
default:
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fieldInfo struct {
|
||||||
|
count uint // Number of bytes
|
||||||
|
countSet bool
|
||||||
|
minlen uint64 // Only relevant for slices
|
||||||
|
maxlen uint64 // Only relevant for slices
|
||||||
|
selector string // Only relevant for select sub-values
|
||||||
|
val uint64 // Only relevant for select sub-values
|
||||||
|
name string // Used for better error messages
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *fieldInfo) fieldName() string {
|
||||||
|
if i == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return i.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a tag string, return a fieldInfo describing the field.
|
||||||
|
func fieldTagToFieldInfo(str string, name string) (*fieldInfo, error) {
|
||||||
|
var info *fieldInfo
|
||||||
|
// Iterate over clauses in the tag, ignoring any that don't parse properly.
|
||||||
|
for _, part := range strings.Split(str, ",") {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(part, "maxval:"):
|
||||||
|
if v, err := strconv.ParseUint(part[7:], 10, 64); err == nil {
|
||||||
|
info = &fieldInfo{count: byteCount(v), countSet: true}
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(part, "size:"):
|
||||||
|
if sz, err := strconv.ParseUint(part[5:], 10, 32); err == nil {
|
||||||
|
info = &fieldInfo{count: uint(sz), countSet: true}
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(part, "maxlen:"):
|
||||||
|
v, err := strconv.ParseUint(part[7:], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info == nil {
|
||||||
|
info = &fieldInfo{}
|
||||||
|
}
|
||||||
|
info.count = byteCount(v)
|
||||||
|
info.countSet = true
|
||||||
|
info.maxlen = v
|
||||||
|
case strings.HasPrefix(part, "minlen:"):
|
||||||
|
v, err := strconv.ParseUint(part[7:], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info == nil {
|
||||||
|
info = &fieldInfo{}
|
||||||
|
}
|
||||||
|
info.minlen = v
|
||||||
|
case strings.HasPrefix(part, "selector:"):
|
||||||
|
if info == nil {
|
||||||
|
info = &fieldInfo{}
|
||||||
|
}
|
||||||
|
info.selector = part[9:]
|
||||||
|
case strings.HasPrefix(part, "val:"):
|
||||||
|
v, err := strconv.ParseUint(part[4:], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info == nil {
|
||||||
|
info = &fieldInfo{}
|
||||||
|
}
|
||||||
|
info.val = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info != nil {
|
||||||
|
info.name = name
|
||||||
|
if info.selector == "" {
|
||||||
|
if info.count < 1 {
|
||||||
|
return nil, structuralError{name, "field of unknown size in " + str}
|
||||||
|
} else if info.count > 8 {
|
||||||
|
return nil, structuralError{name, "specified size too large in " + str}
|
||||||
|
} else if info.minlen > info.maxlen {
|
||||||
|
return nil, structuralError{name, "specified length range inverted in " + str}
|
||||||
|
} else if info.val > 0 {
|
||||||
|
return nil, structuralError{name, "specified selector value but not field in " + str}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if name != "" {
|
||||||
|
info = &fieldInfo{name: name}
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that a value fits into a field described by a fieldInfo structure.
|
||||||
|
func (i fieldInfo) check(val uint64, fldName string) error {
|
||||||
|
if val >= (1 << (8 * i.count)) {
|
||||||
|
return structuralError{fldName, fmt.Sprintf("value %d too large for size", val)}
|
||||||
|
}
|
||||||
|
if i.maxlen != 0 {
|
||||||
|
if val < i.minlen {
|
||||||
|
return structuralError{fldName, fmt.Sprintf("value %d too small for minimum %d", val, i.minlen)}
|
||||||
|
}
|
||||||
|
if val > i.maxlen {
|
||||||
|
return structuralError{fldName, fmt.Sprintf("value %d too large for maximum %d", val, i.maxlen)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readVarUint reads an big-endian unsigned integer of the given size in
|
||||||
|
// bytes.
|
||||||
|
func readVarUint(data []byte, info *fieldInfo) (uint64, error) {
|
||||||
|
if info == nil || !info.countSet {
|
||||||
|
return 0, structuralError{info.fieldName(), "no field size information available"}
|
||||||
|
}
|
||||||
|
if len(data) < int(info.count) {
|
||||||
|
return 0, syntaxError{info.fieldName(), "truncated variable-length integer"}
|
||||||
|
}
|
||||||
|
var result uint64
|
||||||
|
for i := uint(0); i < info.count; i++ {
|
||||||
|
result = (result << 8) | uint64(data[i])
|
||||||
|
}
|
||||||
|
if err := info.check(result, info.name); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseField is the main parsing function. Given a byte slice and an offset
|
||||||
|
// (in bytes) into the data, it will try to parse a suitable ASN.1 value out
|
||||||
|
// and store it in the given Value.
|
||||||
|
func parseField(v reflect.Value, data []byte, initOffset int, info *fieldInfo) (int, error) {
|
||||||
|
offset := initOffset
|
||||||
|
rest := data[offset:]
|
||||||
|
|
||||||
|
fieldType := v.Type()
|
||||||
|
// First look for known fixed types.
|
||||||
|
switch fieldType {
|
||||||
|
case uint8Type:
|
||||||
|
if len(rest) < 1 {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated uint8"}
|
||||||
|
}
|
||||||
|
v.SetUint(uint64(rest[0]))
|
||||||
|
offset++
|
||||||
|
return offset, nil
|
||||||
|
case uint16Type:
|
||||||
|
if len(rest) < 2 {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated uint16"}
|
||||||
|
}
|
||||||
|
v.SetUint(uint64(binary.BigEndian.Uint16(rest)))
|
||||||
|
offset += 2
|
||||||
|
return offset, nil
|
||||||
|
case uint24Type:
|
||||||
|
if len(rest) < 3 {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated uint24"}
|
||||||
|
}
|
||||||
|
v.SetUint(uint64(data[0])<<16 | uint64(data[1])<<8 | uint64(data[2]))
|
||||||
|
offset += 3
|
||||||
|
return offset, nil
|
||||||
|
case uint32Type:
|
||||||
|
if len(rest) < 4 {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated uint32"}
|
||||||
|
}
|
||||||
|
v.SetUint(uint64(binary.BigEndian.Uint32(rest)))
|
||||||
|
offset += 4
|
||||||
|
return offset, nil
|
||||||
|
case uint64Type:
|
||||||
|
if len(rest) < 8 {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated uint64"}
|
||||||
|
}
|
||||||
|
v.SetUint(uint64(binary.BigEndian.Uint64(rest)))
|
||||||
|
offset += 8
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now deal with user-defined types.
|
||||||
|
switch v.Kind() {
|
||||||
|
case enumType.Kind():
|
||||||
|
// Assume that anything of the same kind as Enum is an Enum, so that
|
||||||
|
// users can alias types of their own to Enum.
|
||||||
|
val, err := readVarUint(rest, info)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
v.SetUint(val)
|
||||||
|
offset += int(info.count)
|
||||||
|
return offset, nil
|
||||||
|
case reflect.Struct:
|
||||||
|
structType := fieldType
|
||||||
|
// TLS includes a select(Enum) {..} construct, where the value of an enum
|
||||||
|
// indicates which variant field is present (like a C union). We require
|
||||||
|
// that the enum value be an earlier field in the same structure (the selector),
|
||||||
|
// and that each of the possible variant destination fields be pointers.
|
||||||
|
// So the Go mapping looks like:
|
||||||
|
// type variantType struct {
|
||||||
|
// Which tls.Enum `tls:"size:1"` // this is the selector
|
||||||
|
// Val1 *type1 `tls:"selector:Which,val:1"` // this is a destination
|
||||||
|
// Val2 *type2 `tls:"selector:Which,val:1"` // this is a destination
|
||||||
|
// }
|
||||||
|
|
||||||
|
// To deal with this, we track any enum-like fields and their values...
|
||||||
|
enums := make(map[string]uint64)
|
||||||
|
// .. and we track which selector names we've seen (in the destination field tags),
|
||||||
|
// and whether a destination for that selector has been chosen.
|
||||||
|
selectorSeen := make(map[string]bool)
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
// Find information about this field.
|
||||||
|
tag := structType.Field(i).Tag.Get("tls")
|
||||||
|
fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
|
||||||
|
destination := v.Field(i)
|
||||||
|
if fieldInfo.selector != "" {
|
||||||
|
// This is a possible select(Enum) destination, so first check that the referenced
|
||||||
|
// selector field has already been seen earlier in the struct.
|
||||||
|
choice, ok := enums[fieldInfo.selector]
|
||||||
|
if !ok {
|
||||||
|
return offset, structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector}
|
||||||
|
}
|
||||||
|
if structType.Field(i).Type.Kind() != reflect.Ptr {
|
||||||
|
return offset, structuralError{fieldInfo.name, "choice field not a pointer type"}
|
||||||
|
}
|
||||||
|
// Is this the first mention of the selector field name? If so, remember it.
|
||||||
|
seen, ok := selectorSeen[fieldInfo.selector]
|
||||||
|
if !ok {
|
||||||
|
selectorSeen[fieldInfo.selector] = false
|
||||||
|
}
|
||||||
|
if choice != fieldInfo.val {
|
||||||
|
// This destination field was not the chosen one, so make it nil (we checked
|
||||||
|
// it was a pointer above).
|
||||||
|
v.Field(i).Set(reflect.Zero(structType.Field(i).Type))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if seen {
|
||||||
|
// We already saw a different destination field receive the value for this
|
||||||
|
// selector value, which indicates a badly annotated structure.
|
||||||
|
return offset, structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector}
|
||||||
|
}
|
||||||
|
selectorSeen[fieldInfo.selector] = true
|
||||||
|
// Make an object of the pointed-to type and parse into that.
|
||||||
|
v.Field(i).Set(reflect.New(structType.Field(i).Type.Elem()))
|
||||||
|
destination = v.Field(i).Elem()
|
||||||
|
}
|
||||||
|
offset, err = parseField(destination, data, offset, fieldInfo)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember any possible tls.Enum values encountered in case they are selectors.
|
||||||
|
if structType.Field(i).Type.Kind() == enumType.Kind() {
|
||||||
|
enums[structType.Field(i).Name] = v.Field(i).Uint()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have seen all fields in the structure, check that all select(Enum) {..} selector
|
||||||
|
// fields found a destination to put their data in.
|
||||||
|
for selector, seen := range selectorSeen {
|
||||||
|
if !seen {
|
||||||
|
return offset, syntaxError{info.fieldName(), selector + ": unhandled value for selector"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset, nil
|
||||||
|
case reflect.Array:
|
||||||
|
datalen := v.Len()
|
||||||
|
|
||||||
|
if datalen > len(rest) {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated array"}
|
||||||
|
}
|
||||||
|
inner := rest[:datalen]
|
||||||
|
offset += datalen
|
||||||
|
if fieldType.Elem().Kind() != reflect.Uint8 {
|
||||||
|
// Only byte/uint8 arrays are supported
|
||||||
|
return offset, structuralError{info.fieldName(), "unsupported array type: " + v.Type().String()}
|
||||||
|
}
|
||||||
|
reflect.Copy(v, reflect.ValueOf(inner))
|
||||||
|
return offset, nil
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
sliceType := fieldType
|
||||||
|
// Slices represent variable-length vectors, which are prefixed by a length field.
|
||||||
|
// The fieldInfo indicates the size of that length field.
|
||||||
|
varlen, err := readVarUint(rest, info)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
datalen := int(varlen)
|
||||||
|
offset += int(info.count)
|
||||||
|
rest = rest[info.count:]
|
||||||
|
|
||||||
|
if datalen > len(rest) {
|
||||||
|
return offset, syntaxError{info.fieldName(), "truncated slice"}
|
||||||
|
}
|
||||||
|
inner := rest[:datalen]
|
||||||
|
offset += datalen
|
||||||
|
if fieldType.Elem().Kind() == reflect.Uint8 {
|
||||||
|
// Fast version for []byte
|
||||||
|
v.Set(reflect.MakeSlice(sliceType, datalen, datalen))
|
||||||
|
reflect.Copy(v, reflect.ValueOf(inner))
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Set(reflect.MakeSlice(sliceType, 0, datalen))
|
||||||
|
single := reflect.New(sliceType.Elem())
|
||||||
|
for innerOffset := 0; innerOffset < len(inner); {
|
||||||
|
var err error
|
||||||
|
innerOffset, err = parseField(single.Elem(), inner, innerOffset, nil)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
v.Set(reflect.Append(v, single.Elem()))
|
||||||
|
}
|
||||||
|
return offset, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return offset, structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal returns the TLS encoding of val.
|
||||||
|
func Marshal(val interface{}) ([]byte, error) {
|
||||||
|
return MarshalWithParams(val, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalWithParams returns the TLS encoding of val, and allows field
|
||||||
|
// parameters to be specified for the top-level element. The form
|
||||||
|
// of the params is the same as the field tags.
|
||||||
|
func MarshalWithParams(val interface{}, params string) ([]byte, error) {
|
||||||
|
info, err := fieldTagToFieldInfo(params, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out bytes.Buffer
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
if err := marshalField(&out, v, info); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalField(out *bytes.Buffer, v reflect.Value, info *fieldInfo) error {
|
||||||
|
var prefix string
|
||||||
|
if info != nil && len(info.name) > 0 {
|
||||||
|
prefix = info.name + ": "
|
||||||
|
}
|
||||||
|
fieldType := v.Type()
|
||||||
|
// First look for known fixed types.
|
||||||
|
switch fieldType {
|
||||||
|
case uint8Type:
|
||||||
|
out.WriteByte(byte(v.Uint()))
|
||||||
|
return nil
|
||||||
|
case uint16Type:
|
||||||
|
scratch := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(scratch, uint16(v.Uint()))
|
||||||
|
out.Write(scratch)
|
||||||
|
return nil
|
||||||
|
case uint24Type:
|
||||||
|
i := v.Uint()
|
||||||
|
if i > 0xffffff {
|
||||||
|
return structuralError{info.fieldName(), fmt.Sprintf("uint24 overflow %d", i)}
|
||||||
|
}
|
||||||
|
scratch := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(scratch, uint32(i))
|
||||||
|
out.Write(scratch[1:])
|
||||||
|
return nil
|
||||||
|
case uint32Type:
|
||||||
|
scratch := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(scratch, uint32(v.Uint()))
|
||||||
|
out.Write(scratch)
|
||||||
|
return nil
|
||||||
|
case uint64Type:
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(scratch, uint64(v.Uint()))
|
||||||
|
out.Write(scratch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now deal with user-defined types.
|
||||||
|
switch v.Kind() {
|
||||||
|
case enumType.Kind():
|
||||||
|
i := v.Uint()
|
||||||
|
if info == nil {
|
||||||
|
return structuralError{info.fieldName(), "enum field tag missing"}
|
||||||
|
}
|
||||||
|
if err := info.check(i, prefix); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(scratch, uint64(i))
|
||||||
|
out.Write(scratch[(8 - info.count):])
|
||||||
|
return nil
|
||||||
|
case reflect.Struct:
|
||||||
|
structType := fieldType
|
||||||
|
enums := make(map[string]uint64) // Values of any Enum fields
|
||||||
|
// The comment parseField() describes the mapping of the TLS select(Enum) {..} construct;
|
||||||
|
// here we have selector and source (rather than destination) fields.
|
||||||
|
|
||||||
|
// Track which selector names we've seen (in the source field tags), and whether a source
|
||||||
|
// value for that selector has been processed.
|
||||||
|
selectorSeen := make(map[string]bool)
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
// Find information about this field.
|
||||||
|
tag := structType.Field(i).Tag.Get("tls")
|
||||||
|
fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
source := v.Field(i)
|
||||||
|
if fieldInfo.selector != "" {
|
||||||
|
// This field is a possible source for a select(Enum) {..}. First check
|
||||||
|
// the selector field name has been seen.
|
||||||
|
choice, ok := enums[fieldInfo.selector]
|
||||||
|
if !ok {
|
||||||
|
return structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector}
|
||||||
|
}
|
||||||
|
if structType.Field(i).Type.Kind() != reflect.Ptr {
|
||||||
|
return structuralError{fieldInfo.name, "choice field not a pointer type"}
|
||||||
|
}
|
||||||
|
// Is this the first mention of the selector field name? If so, remember it.
|
||||||
|
seen, ok := selectorSeen[fieldInfo.selector]
|
||||||
|
if !ok {
|
||||||
|
selectorSeen[fieldInfo.selector] = false
|
||||||
|
}
|
||||||
|
if choice != fieldInfo.val {
|
||||||
|
// This source was not chosen; police that it should be nil.
|
||||||
|
if v.Field(i).Pointer() != uintptr(0) {
|
||||||
|
return structuralError{fieldInfo.name, "unchosen field is non-nil"}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if seen {
|
||||||
|
// We already saw a different source field generate the value for this
|
||||||
|
// selector value, which indicates a badly annotated structure.
|
||||||
|
return structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector}
|
||||||
|
}
|
||||||
|
selectorSeen[fieldInfo.selector] = true
|
||||||
|
if v.Field(i).Pointer() == uintptr(0) {
|
||||||
|
return structuralError{fieldInfo.name, "chosen field is nil"}
|
||||||
|
}
|
||||||
|
// Marshal from the pointed-to source object.
|
||||||
|
source = v.Field(i).Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldData bytes.Buffer
|
||||||
|
if err := marshalField(&fieldData, source, fieldInfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out.Write(fieldData.Bytes())
|
||||||
|
|
||||||
|
// Remember any tls.Enum values encountered in case they are selectors.
|
||||||
|
if structType.Field(i).Type.Kind() == enumType.Kind() {
|
||||||
|
enums[structType.Field(i).Name] = v.Field(i).Uint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now we have seen all fields in the structure, check that all select(Enum) {..} selector
|
||||||
|
// fields found a source field get get their data from.
|
||||||
|
for selector, seen := range selectorSeen {
|
||||||
|
if !seen {
|
||||||
|
return syntaxError{info.fieldName(), selector + ": unhandled value for selector"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
datalen := v.Len()
|
||||||
|
arrayType := fieldType
|
||||||
|
if arrayType.Elem().Kind() != reflect.Uint8 {
|
||||||
|
// Only byte/uint8 arrays are supported
|
||||||
|
return structuralError{info.fieldName(), "unsupported array type"}
|
||||||
|
}
|
||||||
|
bytes := make([]byte, datalen)
|
||||||
|
for i := 0; i < datalen; i++ {
|
||||||
|
bytes[i] = uint8(v.Index(i).Uint())
|
||||||
|
}
|
||||||
|
_, err := out.Write(bytes)
|
||||||
|
return err
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if info == nil {
|
||||||
|
return structuralError{info.fieldName(), "slice field tag missing"}
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceType := fieldType
|
||||||
|
if sliceType.Elem().Kind() == reflect.Uint8 {
|
||||||
|
// Fast version for []byte: first write the length as info.count bytes.
|
||||||
|
datalen := v.Len()
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(scratch, uint64(datalen))
|
||||||
|
out.Write(scratch[(8 - info.count):])
|
||||||
|
|
||||||
|
if err := info.check(uint64(datalen), prefix); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Then just write the data.
|
||||||
|
bytes := make([]byte, datalen)
|
||||||
|
for i := 0; i < datalen; i++ {
|
||||||
|
bytes[i] = uint8(v.Index(i).Uint())
|
||||||
|
}
|
||||||
|
_, err := out.Write(bytes)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// General version: use a separate Buffer to write the slice entries into.
|
||||||
|
var innerBuf bytes.Buffer
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
if err := marshalField(&innerBuf, v.Index(i), nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now insert (and check) the size.
|
||||||
|
size := uint64(innerBuf.Len())
|
||||||
|
if err := info.check(size, prefix); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(scratch, size)
|
||||||
|
out.Write(scratch[(8 - info.count):])
|
||||||
|
|
||||||
|
// Then copy the data.
|
||||||
|
_, err := out.Write(innerBuf.Bytes())
|
||||||
|
return err
|
||||||
|
|
||||||
|
default:
|
||||||
|
return structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())}
|
||||||
|
}
|
||||||
|
}
|
||||||
96
vendor/github.com/google/certificate-transparency-go/tls/types.go
generated
vendored
Normal file
96
vendor/github.com/google/certificate-transparency-go/tls/types.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// DigitallySigned gives information about a signature, including the algorithm used
|
||||||
|
// and the signature value. Defined in RFC 5246 s4.7.
|
||||||
|
type DigitallySigned struct {
|
||||||
|
Algorithm SignatureAndHashAlgorithm
|
||||||
|
Signature []byte `tls:"minlen:0,maxlen:65535"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DigitallySigned) String() string {
|
||||||
|
return fmt.Sprintf("Signature: HashAlgo=%v SignAlgo=%v Value=%x", d.Algorithm.Hash, d.Algorithm.Signature, d.Signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureAndHashAlgorithm gives information about the algorithms used for a
|
||||||
|
// signature. Defined in RFC 5246 s7.4.1.4.1.
|
||||||
|
type SignatureAndHashAlgorithm struct {
|
||||||
|
Hash HashAlgorithm `tls:"maxval:255"`
|
||||||
|
Signature SignatureAlgorithm `tls:"maxval:255"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashAlgorithm enum from RFC 5246 s7.4.1.4.1.
|
||||||
|
type HashAlgorithm Enum
|
||||||
|
|
||||||
|
// HashAlgorithm constants from RFC 5246 s7.4.1.4.1.
|
||||||
|
const (
|
||||||
|
None HashAlgorithm = 0
|
||||||
|
MD5 HashAlgorithm = 1
|
||||||
|
SHA1 HashAlgorithm = 2
|
||||||
|
SHA224 HashAlgorithm = 3
|
||||||
|
SHA256 HashAlgorithm = 4
|
||||||
|
SHA384 HashAlgorithm = 5
|
||||||
|
SHA512 HashAlgorithm = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h HashAlgorithm) String() string {
|
||||||
|
switch h {
|
||||||
|
case None:
|
||||||
|
return "None"
|
||||||
|
case MD5:
|
||||||
|
return "MD5"
|
||||||
|
case SHA1:
|
||||||
|
return "SHA1"
|
||||||
|
case SHA224:
|
||||||
|
return "SHA224"
|
||||||
|
case SHA256:
|
||||||
|
return "SHA256"
|
||||||
|
case SHA384:
|
||||||
|
return "SHA384"
|
||||||
|
case SHA512:
|
||||||
|
return "SHA512"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UNKNOWN(%d)", h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureAlgorithm enum from RFC 5246 s7.4.1.4.1.
|
||||||
|
type SignatureAlgorithm Enum
|
||||||
|
|
||||||
|
// SignatureAlgorithm constants from RFC 5246 s7.4.1.4.1.
|
||||||
|
const (
|
||||||
|
Anonymous SignatureAlgorithm = 0
|
||||||
|
RSA SignatureAlgorithm = 1
|
||||||
|
DSA SignatureAlgorithm = 2
|
||||||
|
ECDSA SignatureAlgorithm = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s SignatureAlgorithm) String() string {
|
||||||
|
switch s {
|
||||||
|
case Anonymous:
|
||||||
|
return "Anonymous"
|
||||||
|
case RSA:
|
||||||
|
return "RSA"
|
||||||
|
case DSA:
|
||||||
|
return "DSA"
|
||||||
|
case ECDSA:
|
||||||
|
return "ECDSA"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UNKNOWN(%d)", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
460
vendor/github.com/google/certificate-transparency-go/types.go
generated
vendored
Normal file
460
vendor/github.com/google/certificate-transparency-go/types.go
generated
vendored
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package ct holds core types and utilities for Certificate Transparency.
|
||||||
|
package ct
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/tls"
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The following structures represent those outlined in RFC6962; any section
|
||||||
|
// numbers mentioned refer to that RFC.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// LogEntryType represents the LogEntryType enum from section 3.1:
|
||||||
|
// enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
|
||||||
|
type LogEntryType tls.Enum // tls:"maxval:65535"
|
||||||
|
|
||||||
|
// LogEntryType constants from section 3.1.
|
||||||
|
const (
|
||||||
|
X509LogEntryType LogEntryType = 0
|
||||||
|
PrecertLogEntryType LogEntryType = 1
|
||||||
|
XJSONLogEntryType LogEntryType = 0x8000 // Experimental. Don't rely on this!
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e LogEntryType) String() string {
|
||||||
|
switch e {
|
||||||
|
case X509LogEntryType:
|
||||||
|
return "X509LogEntryType"
|
||||||
|
case PrecertLogEntryType:
|
||||||
|
return "PrecertLogEntryType"
|
||||||
|
case XJSONLogEntryType:
|
||||||
|
return "XJSONLogEntryType"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UnknownEntryType(%d)", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MerkleLeafType represents the MerkleLeafType enum from section 3.4:
|
||||||
|
// enum { timestamped_entry(0), (255) } MerkleLeafType;
|
||||||
|
type MerkleLeafType tls.Enum // tls:"maxval:255"
|
||||||
|
|
||||||
|
// TimestampedEntryLeafType is the only defined MerkleLeafType constant from section 3.4.
|
||||||
|
const TimestampedEntryLeafType MerkleLeafType = 0 // Entry type for an SCT
|
||||||
|
|
||||||
|
func (m MerkleLeafType) String() string {
|
||||||
|
switch m {
|
||||||
|
case TimestampedEntryLeafType:
|
||||||
|
return "TimestampedEntryLeafType"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UnknownLeafType(%d)", m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version represents the Version enum from section 3.2:
|
||||||
|
// enum { v1(0), (255) } Version;
|
||||||
|
type Version tls.Enum // tls:"maxval:255"
|
||||||
|
|
||||||
|
// CT Version constants from section 3.2.
|
||||||
|
const (
|
||||||
|
V1 Version = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
switch v {
|
||||||
|
case V1:
|
||||||
|
return "V1"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UnknownVersion(%d)", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureType differentiates STH signatures from SCT signatures, see section 3.2.
|
||||||
|
// enum { certificate_timestamp(0), tree_hash(1), (255) } SignatureType;
|
||||||
|
type SignatureType tls.Enum // tls:"maxval:255"
|
||||||
|
|
||||||
|
// SignatureType constants from section 3.2.
|
||||||
|
const (
|
||||||
|
CertificateTimestampSignatureType SignatureType = 0
|
||||||
|
TreeHashSignatureType SignatureType = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (st SignatureType) String() string {
|
||||||
|
switch st {
|
||||||
|
case CertificateTimestampSignatureType:
|
||||||
|
return "CertificateTimestamp"
|
||||||
|
case TreeHashSignatureType:
|
||||||
|
return "TreeHash"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("UnknownSignatureType(%d)", st)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASN1Cert type for holding the raw DER bytes of an ASN.1 Certificate
|
||||||
|
// (section 3.1).
|
||||||
|
type ASN1Cert struct {
|
||||||
|
Data []byte `tls:"minlen:1,maxlen:16777215"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogID holds the hash of the Log's public key (section 3.2).
|
||||||
|
// TODO(pphaneuf): Users should be migrated to the one in the logid package.
|
||||||
|
type LogID struct {
|
||||||
|
KeyID [sha256.Size]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreCert represents a Precertificate (section 3.2).
|
||||||
|
type PreCert struct {
|
||||||
|
IssuerKeyHash [sha256.Size]byte
|
||||||
|
TBSCertificate []byte `tls:"minlen:1,maxlen:16777215"` // DER-encoded TBSCertificate
|
||||||
|
}
|
||||||
|
|
||||||
|
// CTExtensions is a representation of the raw bytes of any CtExtension
|
||||||
|
// structure (see section 3.2).
|
||||||
|
// nolint: golint
|
||||||
|
type CTExtensions []byte // tls:"minlen:0,maxlen:65535"`
|
||||||
|
|
||||||
|
// MerkleTreeNode represents an internal node in the CT tree.
|
||||||
|
type MerkleTreeNode []byte
|
||||||
|
|
||||||
|
// ConsistencyProof represents a CT consistency proof (see sections 2.1.2 and
|
||||||
|
// 4.4).
|
||||||
|
type ConsistencyProof []MerkleTreeNode
|
||||||
|
|
||||||
|
// AuditPath represents a CT inclusion proof (see sections 2.1.1 and 4.5).
|
||||||
|
type AuditPath []MerkleTreeNode
|
||||||
|
|
||||||
|
// LeafInput represents a serialized MerkleTreeLeaf structure.
|
||||||
|
type LeafInput []byte
|
||||||
|
|
||||||
|
// DigitallySigned is a local alias for tls.DigitallySigned so that we can
|
||||||
|
// attach a MarshalJSON method.
|
||||||
|
type DigitallySigned tls.DigitallySigned
|
||||||
|
|
||||||
|
// FromBase64String populates the DigitallySigned structure from the base64 data passed in.
|
||||||
|
// Returns an error if the base64 data is invalid.
|
||||||
|
func (d *DigitallySigned) FromBase64String(b64 string) error {
|
||||||
|
raw, err := base64.StdEncoding.DecodeString(b64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err)
|
||||||
|
}
|
||||||
|
var ds tls.DigitallySigned
|
||||||
|
if rest, err := tls.Unmarshal(raw, &ds); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
||||||
|
} else if len(rest) > 0 {
|
||||||
|
return fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest))
|
||||||
|
}
|
||||||
|
*d = DigitallySigned(ds)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64String returns the base64 representation of the DigitallySigned struct.
|
||||||
|
func (d DigitallySigned) Base64String() (string, error) {
|
||||||
|
b, err := tls.Marshal(d)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaller interface.
|
||||||
|
func (d DigitallySigned) MarshalJSON() ([]byte, error) {
|
||||||
|
b64, err := d.Base64String()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return []byte(`"` + b64 + `"`), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (d *DigitallySigned) UnmarshalJSON(b []byte) error {
|
||||||
|
var content string
|
||||||
|
if err := json.Unmarshal(b, &content); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
||||||
|
}
|
||||||
|
return d.FromBase64String(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogEntry represents the (parsed) contents of an entry in a CT log. This is described
|
||||||
|
// in section 3.1, but note that this structure does *not* match the TLS structure
|
||||||
|
// defined there (the TLS structure is never used directly in RFC6962).
|
||||||
|
type LogEntry struct {
|
||||||
|
Index int64
|
||||||
|
Leaf MerkleTreeLeaf
|
||||||
|
// Exactly one of the following three fields should be non-empty.
|
||||||
|
X509Cert *x509.Certificate // Parsed X.509 certificate
|
||||||
|
Precert *Precertificate // Extracted precertificate
|
||||||
|
JSONData []byte
|
||||||
|
|
||||||
|
// Chain holds the issuing certificate chain, starting with the
|
||||||
|
// issuer of the leaf certificate / pre-certificate.
|
||||||
|
Chain []ASN1Cert
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrecertChainEntry holds an precertificate together with a validation chain
|
||||||
|
// for it; see section 3.1.
|
||||||
|
type PrecertChainEntry struct {
|
||||||
|
PreCertificate ASN1Cert `tls:"minlen:1,maxlen:16777215"`
|
||||||
|
CertificateChain []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateChain holds a chain of certificates, as returned as extra data
|
||||||
|
// for get-entries (section 4.6).
|
||||||
|
type CertificateChain struct {
|
||||||
|
Entries []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONDataEntry holds arbitrary data.
|
||||||
|
type JSONDataEntry struct {
|
||||||
|
Data []byte `tls:"minlen:0,maxlen:1677215"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA256Hash represents the output from the SHA256 hash function.
|
||||||
|
type SHA256Hash [sha256.Size]byte
|
||||||
|
|
||||||
|
// FromBase64String populates the SHA256 struct with the contents of the base64 data passed in.
|
||||||
|
func (s *SHA256Hash) FromBase64String(b64 string) error {
|
||||||
|
bs, err := base64.StdEncoding.DecodeString(b64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unbase64 LogID: %v", err)
|
||||||
|
}
|
||||||
|
if len(bs) != sha256.Size {
|
||||||
|
return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs))
|
||||||
|
}
|
||||||
|
copy(s[:], bs)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64String returns the base64 representation of this SHA256Hash.
|
||||||
|
func (s SHA256Hash) Base64String() string {
|
||||||
|
return base64.StdEncoding.EncodeToString(s[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaller interface for SHA256Hash.
|
||||||
|
func (s SHA256Hash) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(`"` + s.Base64String() + `"`), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||||
|
func (s *SHA256Hash) UnmarshalJSON(b []byte) error {
|
||||||
|
var content string
|
||||||
|
if err := json.Unmarshal(b, &content); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err)
|
||||||
|
}
|
||||||
|
return s.FromBase64String(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedTreeHead represents the structure returned by the get-sth CT method
|
||||||
|
// after base64 decoding; see sections 3.5 and 4.3.
|
||||||
|
type SignedTreeHead struct {
|
||||||
|
Version Version `json:"sth_version"` // The version of the protocol to which the STH conforms
|
||||||
|
TreeSize uint64 `json:"tree_size"` // The number of entries in the new tree
|
||||||
|
Timestamp uint64 `json:"timestamp"` // The time at which the STH was created
|
||||||
|
SHA256RootHash SHA256Hash `json:"sha256_root_hash"` // The root hash of the log's Merkle tree
|
||||||
|
TreeHeadSignature DigitallySigned `json:"tree_head_signature"` // Log's signature over a TLS-encoded TreeHeadSignature
|
||||||
|
LogID SHA256Hash `json:"log_id"` // The SHA256 hash of the log's public key
|
||||||
|
}
|
||||||
|
|
||||||
|
// TreeHeadSignature holds the data over which the signature in an STH is
|
||||||
|
// generated; see section 3.5
|
||||||
|
type TreeHeadSignature struct {
|
||||||
|
Version Version `tls:"maxval:255"`
|
||||||
|
SignatureType SignatureType `tls:"maxval:255"` // == TreeHashSignatureType
|
||||||
|
Timestamp uint64
|
||||||
|
TreeSize uint64
|
||||||
|
SHA256RootHash SHA256Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedCertificateTimestamp represents the structure returned by the
|
||||||
|
// add-chain and add-pre-chain methods after base64 decoding; see sections
|
||||||
|
// 3.2, 4.1 and 4.2.
|
||||||
|
type SignedCertificateTimestamp struct {
|
||||||
|
SCTVersion Version `tls:"maxval:255"`
|
||||||
|
LogID LogID
|
||||||
|
Timestamp uint64
|
||||||
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
||||||
|
Signature DigitallySigned // Signature over TLS-encoded CertificateTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateTimestamp is the collection of data that the signature in an
|
||||||
|
// SCT is over; see section 3.2.
|
||||||
|
type CertificateTimestamp struct {
|
||||||
|
SCTVersion Version `tls:"maxval:255"`
|
||||||
|
SignatureType SignatureType `tls:"maxval:255"`
|
||||||
|
Timestamp uint64
|
||||||
|
EntryType LogEntryType `tls:"maxval:65535"`
|
||||||
|
X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"`
|
||||||
|
PrecertEntry *PreCert `tls:"selector:EntryType,val:1"`
|
||||||
|
JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"`
|
||||||
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SignedCertificateTimestamp) String() string {
|
||||||
|
return fmt.Sprintf("{Version:%d LogId:%s Timestamp:%d Extensions:'%s' Signature:%v}", s.SCTVersion,
|
||||||
|
base64.StdEncoding.EncodeToString(s.LogID.KeyID[:]),
|
||||||
|
s.Timestamp,
|
||||||
|
s.Extensions,
|
||||||
|
s.Signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampedEntry is part of the MerkleTreeLeaf structure; see section 3.4.
|
||||||
|
type TimestampedEntry struct {
|
||||||
|
Timestamp uint64
|
||||||
|
EntryType LogEntryType `tls:"maxval:65535"`
|
||||||
|
X509Entry *ASN1Cert `tls:"selector:EntryType,val:0"`
|
||||||
|
PrecertEntry *PreCert `tls:"selector:EntryType,val:1"`
|
||||||
|
JSONEntry *JSONDataEntry `tls:"selector:EntryType,val:32768"`
|
||||||
|
Extensions CTExtensions `tls:"minlen:0,maxlen:65535"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MerkleTreeLeaf represents the deserialized structure of the hash input for the
|
||||||
|
// leaves of a log's Merkle tree; see section 3.4.
|
||||||
|
type MerkleTreeLeaf struct {
|
||||||
|
Version Version `tls:"maxval:255"`
|
||||||
|
LeafType MerkleLeafType `tls:"maxval:255"`
|
||||||
|
TimestampedEntry *TimestampedEntry `tls:"selector:LeafType,val:0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precertificate represents the parsed CT Precertificate structure.
|
||||||
|
type Precertificate struct {
|
||||||
|
// DER-encoded pre-certificate as originally added, which includes a
|
||||||
|
// poison extension and a signature generated over the pre-cert by
|
||||||
|
// the pre-cert issuer (which might differ from the issuer of the final
|
||||||
|
// cert, see RFC6962 s3.1).
|
||||||
|
Submitted ASN1Cert
|
||||||
|
// SHA256 hash of the issuing key
|
||||||
|
IssuerKeyHash [sha256.Size]byte
|
||||||
|
// Parsed TBSCertificate structure, held in an x509.Certificate for convenience.
|
||||||
|
TBSCertificate *x509.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
// X509Certificate returns the X.509 Certificate contained within the
|
||||||
|
// MerkleTreeLeaf.
|
||||||
|
func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) {
|
||||||
|
if m.TimestampedEntry.EntryType != X509LogEntryType {
|
||||||
|
return nil, fmt.Errorf("cannot call X509Certificate on a MerkleTreeLeaf that is not an X509 entry")
|
||||||
|
}
|
||||||
|
return x509.ParseCertificate(m.TimestampedEntry.X509Entry.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precertificate returns the X.509 Precertificate contained within the MerkleTreeLeaf.
|
||||||
|
//
|
||||||
|
// The returned precertificate is embedded in an x509.Certificate, but is in the
|
||||||
|
// form stored internally in the log rather than the original submitted form
|
||||||
|
// (i.e. it does not include the poison extension and any changes to reflect the
|
||||||
|
// final certificate's issuer have been made; see x509.BuildPrecertTBS).
|
||||||
|
func (m *MerkleTreeLeaf) Precertificate() (*x509.Certificate, error) {
|
||||||
|
if m.TimestampedEntry.EntryType != PrecertLogEntryType {
|
||||||
|
return nil, fmt.Errorf("cannot call Precertificate on a MerkleTreeLeaf that is not a precert entry")
|
||||||
|
}
|
||||||
|
return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI paths for Log requests; see section 4.
|
||||||
|
const (
|
||||||
|
AddChainPath = "/ct/v1/add-chain"
|
||||||
|
AddPreChainPath = "/ct/v1/add-pre-chain"
|
||||||
|
GetSTHPath = "/ct/v1/get-sth"
|
||||||
|
GetEntriesPath = "/ct/v1/get-entries"
|
||||||
|
GetProofByHashPath = "/ct/v1/get-proof-by-hash"
|
||||||
|
GetSTHConsistencyPath = "/ct/v1/get-sth-consistency"
|
||||||
|
GetRootsPath = "/ct/v1/get-roots"
|
||||||
|
GetEntryAndProofPath = "/ct/v1/get-entry-and-proof"
|
||||||
|
|
||||||
|
AddJSONPath = "/ct/v1/add-json" // Experimental addition
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddChainRequest represents the JSON request body sent to the add-chain and
|
||||||
|
// add-pre-chain POST methods from sections 4.1 and 4.2.
|
||||||
|
type AddChainRequest struct {
|
||||||
|
Chain [][]byte `json:"chain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddChainResponse represents the JSON response to the add-chain and
|
||||||
|
// add-pre-chain POST methods.
|
||||||
|
// An SCT represents a Log's promise to integrate a [pre-]certificate into the
|
||||||
|
// log within a defined period of time.
|
||||||
|
type AddChainResponse struct {
|
||||||
|
SCTVersion Version `json:"sct_version"` // SCT structure version
|
||||||
|
ID []byte `json:"id"` // Log ID
|
||||||
|
Timestamp uint64 `json:"timestamp"` // Timestamp of issuance
|
||||||
|
Extensions string `json:"extensions"` // Holder for any CT extensions
|
||||||
|
Signature []byte `json:"signature"` // Log signature for this SCT
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddJSONRequest represents the JSON request body sent to the add-json POST method.
|
||||||
|
// The corresponding response re-uses AddChainResponse.
|
||||||
|
// This is an experimental addition not covered by RFC6962.
|
||||||
|
type AddJSONRequest struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSTHResponse respresents the JSON response to the get-sth GET method from section 4.3.
|
||||||
|
type GetSTHResponse struct {
|
||||||
|
TreeSize uint64 `json:"tree_size"` // Number of certs in the current tree
|
||||||
|
Timestamp uint64 `json:"timestamp"` // Time that the tree was created
|
||||||
|
SHA256RootHash []byte `json:"sha256_root_hash"` // Root hash of the tree
|
||||||
|
TreeHeadSignature []byte `json:"tree_head_signature"` // Log signature for this STH
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSTHConsistencyResponse represents the JSON response to the get-sth-consistency
|
||||||
|
// GET method from section 4.4. (The corresponding GET request has parameters 'first' and
|
||||||
|
// 'second'.)
|
||||||
|
type GetSTHConsistencyResponse struct {
|
||||||
|
Consistency [][]byte `json:"consistency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProofByHashResponse represents the JSON response to the get-proof-by-hash GET
|
||||||
|
// method from section 4.5. (The corresponding GET request has parameters 'hash'
|
||||||
|
// and 'tree_size'.)
|
||||||
|
type GetProofByHashResponse struct {
|
||||||
|
LeafIndex int64 `json:"leaf_index"` // The 0-based index of the end entity corresponding to the "hash" parameter.
|
||||||
|
AuditPath [][]byte `json:"audit_path"` // An array of base64-encoded Merkle Tree nodes proving the inclusion of the chosen certificate.
|
||||||
|
}
|
||||||
|
|
||||||
|
// LeafEntry represents a leaf in the Log's Merkle tree, as returned by the get-entries
|
||||||
|
// GET method from section 4.6.
|
||||||
|
type LeafEntry struct {
|
||||||
|
// LeafInput is a TLS-encoded MerkleTreeLeaf
|
||||||
|
LeafInput []byte `json:"leaf_input"`
|
||||||
|
// ExtraData holds (unsigned) extra data, normally the cert validation chain.
|
||||||
|
ExtraData []byte `json:"extra_data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEntriesResponse respresents the JSON response to the get-entries GET method
|
||||||
|
// from section 4.6.
|
||||||
|
type GetEntriesResponse struct {
|
||||||
|
Entries []LeafEntry `json:"entries"` // the list of returned entries
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootsResponse represents the JSON response to the get-roots GET method from section 4.7.
|
||||||
|
type GetRootsResponse struct {
|
||||||
|
Certificates []string `json:"certificates"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEntryAndProofResponse represents the JSON response to the get-entry-and-proof
|
||||||
|
// GET method from section 4.8. (The corresponding GET request has parameters 'leaf_index'
|
||||||
|
// and 'tree_size'.)
|
||||||
|
type GetEntryAndProofResponse struct {
|
||||||
|
LeafInput []byte `json:"leaf_input"` // the entry itself
|
||||||
|
ExtraData []byte `json:"extra_data"` // any chain provided when the entry was added to the log
|
||||||
|
AuditPath [][]byte `json:"audit_path"` // the corresponding proof
|
||||||
|
}
|
||||||
122
vendor/github.com/google/certificate-transparency-go/x509/BUILD
generated
vendored
Normal file
122
vendor/github.com/google/certificate-transparency-go/x509/BUILD
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"cert_pool.go",
|
||||||
|
"error.go",
|
||||||
|
"errors.go",
|
||||||
|
"names.go",
|
||||||
|
"pem_decrypt.go",
|
||||||
|
"pkcs1.go",
|
||||||
|
"pkcs8.go",
|
||||||
|
"revoked.go",
|
||||||
|
"root.go",
|
||||||
|
"sec1.go",
|
||||||
|
"verify.go",
|
||||||
|
"x509.go",
|
||||||
|
] + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin": [
|
||||||
|
"root_darwin.go",
|
||||||
|
"root_nocgo_darwin.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||||
|
"root_bsd.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||||
|
"root_bsd.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:linux": [
|
||||||
|
"root_linux.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:nacl": [
|
||||||
|
"root_nacl.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||||
|
"root_bsd.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||||
|
"root_bsd.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:plan9": [
|
||||||
|
"root_plan9.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:solaris": [
|
||||||
|
"root_solaris.go",
|
||||||
|
"root_unix.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:windows": [
|
||||||
|
"root_windows.go",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}) + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_386": [
|
||||||
|
"nilref_nil_darwin.go",
|
||||||
|
"nilref_zero_darwin.go",
|
||||||
|
"root_cgo_darwin.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_amd64": [
|
||||||
|
"nilref_nil_darwin.go",
|
||||||
|
"nilref_zero_darwin.go",
|
||||||
|
"root_cgo_darwin.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_arm": [
|
||||||
|
"root_darwin_armx.go",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_arm64": [
|
||||||
|
"root_darwin_armx.go",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
cgo = True,
|
||||||
|
clinkopts = select({
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_386": [
|
||||||
|
"-framework CoreFoundation -framework Security",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_amd64": [
|
||||||
|
"-framework CoreFoundation -framework Security",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
copts = select({
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_386": [
|
||||||
|
"-mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin_amd64": [
|
||||||
|
"-mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
importpath = "github.com/google/certificate-transparency-go/x509",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/asn1:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/tls:go_default_library",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/x509/pkix:go_default_library",
|
||||||
|
"//vendor/golang.org/x/crypto/cryptobyte:go_default_library",
|
||||||
|
"//vendor/golang.org/x/crypto/cryptobyte/asn1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//vendor/github.com/google/certificate-transparency-go/x509/pkix:all-srcs",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
47
vendor/github.com/google/certificate-transparency/go/x509/cert_pool.go → vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go
generated
vendored
Executable file → Normal file
47
vendor/github.com/google/certificate-transparency/go/x509/cert_pool.go → vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go
generated
vendored
Executable file → Normal file
@@ -6,6 +6,8 @@ package x509
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CertPool is a set of certificates.
|
// CertPool is a set of certificates.
|
||||||
@@ -18,12 +20,24 @@ type CertPool struct {
|
|||||||
// NewCertPool returns a new, empty CertPool.
|
// NewCertPool returns a new, empty CertPool.
|
||||||
func NewCertPool() *CertPool {
|
func NewCertPool() *CertPool {
|
||||||
return &CertPool{
|
return &CertPool{
|
||||||
make(map[string][]int),
|
bySubjectKeyId: make(map[string][]int),
|
||||||
make(map[string][]int),
|
byName: make(map[string][]int),
|
||||||
nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SystemCertPool returns a copy of the system cert pool.
|
||||||
|
//
|
||||||
|
// Any mutations to the returned pool are not written to disk and do
|
||||||
|
// not affect any other pool.
|
||||||
|
func SystemCertPool() (*CertPool, error) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// Issue 16736, 18609:
|
||||||
|
return nil, errors.New("crypto/x509: system root pool is not available on Windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadSystemRoots()
|
||||||
|
}
|
||||||
|
|
||||||
// findVerifiedParents attempts to find certificates in s which have signed the
|
// findVerifiedParents attempts to find certificates in s which have signed the
|
||||||
// given certificate. If any candidates were rejected then errCert will be set
|
// given certificate. If any candidates were rejected then errCert will be set
|
||||||
// to one of them, arbitrarily, and err will contain the reason that it was
|
// to one of them, arbitrarily, and err will contain the reason that it was
|
||||||
@@ -52,6 +66,21 @@ func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCer
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CertPool) contains(cert *Certificate) bool {
|
||||||
|
if s == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates := s.byName[string(cert.RawSubject)]
|
||||||
|
for _, c := range candidates {
|
||||||
|
if s.certs[c].Equal(cert) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// AddCert adds a certificate to a pool.
|
// AddCert adds a certificate to a pool.
|
||||||
func (s *CertPool) AddCert(cert *Certificate) {
|
func (s *CertPool) AddCert(cert *Certificate) {
|
||||||
if cert == nil {
|
if cert == nil {
|
||||||
@@ -59,11 +88,9 @@ func (s *CertPool) AddCert(cert *Certificate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that the certificate isn't being added twice.
|
// Check that the certificate isn't being added twice.
|
||||||
for _, c := range s.certs {
|
if s.contains(cert) {
|
||||||
if c.Equal(cert) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
n := len(s.certs)
|
n := len(s.certs)
|
||||||
s.certs = append(s.certs, cert)
|
s.certs = append(s.certs, cert)
|
||||||
@@ -77,7 +104,7 @@ func (s *CertPool) AddCert(cert *Certificate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
|
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
|
||||||
// It appends any certificates found to s and returns true if any certificates
|
// It appends any certificates found to s and reports whether any certificates
|
||||||
// were successfully parsed.
|
// were successfully parsed.
|
||||||
//
|
//
|
||||||
// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
|
// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
|
||||||
@@ -107,10 +134,10 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
|
|||||||
|
|
||||||
// Subjects returns a list of the DER-encoded subjects of
|
// Subjects returns a list of the DER-encoded subjects of
|
||||||
// all of the certificates in the pool.
|
// all of the certificates in the pool.
|
||||||
func (s *CertPool) Subjects() (res [][]byte) {
|
func (s *CertPool) Subjects() [][]byte {
|
||||||
res = make([][]byte, len(s.certs))
|
res := make([][]byte, len(s.certs))
|
||||||
for i, c := range s.certs {
|
for i, c := range s.certs {
|
||||||
res[i] = c.RawSubject
|
res[i] = c.RawSubject
|
||||||
}
|
}
|
||||||
return
|
return res
|
||||||
}
|
}
|
||||||
230
vendor/github.com/google/certificate-transparency-go/x509/error.go
generated
vendored
Normal file
230
vendor/github.com/google/certificate-transparency-go/x509/error.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error implements the error interface and describes a single error in an X.509 certificate or CRL.
|
||||||
|
type Error struct {
|
||||||
|
ID ErrorID
|
||||||
|
Category ErrCategory
|
||||||
|
Summary string
|
||||||
|
Field string
|
||||||
|
SpecRef string
|
||||||
|
SpecText string
|
||||||
|
// Fatal indicates that parsing has been aborted.
|
||||||
|
Fatal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err Error) Error() string {
|
||||||
|
var msg bytes.Buffer
|
||||||
|
if err.ID != ErrInvalidID {
|
||||||
|
if err.Fatal {
|
||||||
|
msg.WriteRune('E')
|
||||||
|
} else {
|
||||||
|
msg.WriteRune('W')
|
||||||
|
}
|
||||||
|
msg.WriteString(fmt.Sprintf("%03d: ", err.ID))
|
||||||
|
}
|
||||||
|
msg.WriteString(err.Summary)
|
||||||
|
return msg.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerboseError creates a more verbose error string, including spec details.
|
||||||
|
func (err Error) VerboseError() string {
|
||||||
|
var msg bytes.Buffer
|
||||||
|
msg.WriteString(err.Error())
|
||||||
|
if len(err.Field) > 0 || err.Category != UnknownCategory || len(err.SpecRef) > 0 || len(err.SpecText) > 0 {
|
||||||
|
msg.WriteString(" (")
|
||||||
|
needSep := false
|
||||||
|
if len(err.Field) > 0 {
|
||||||
|
msg.WriteString(err.Field)
|
||||||
|
needSep = true
|
||||||
|
}
|
||||||
|
if err.Category != UnknownCategory {
|
||||||
|
if needSep {
|
||||||
|
msg.WriteString(": ")
|
||||||
|
}
|
||||||
|
msg.WriteString(err.Category.String())
|
||||||
|
needSep = true
|
||||||
|
}
|
||||||
|
if len(err.SpecRef) > 0 {
|
||||||
|
if needSep {
|
||||||
|
msg.WriteString(": ")
|
||||||
|
}
|
||||||
|
msg.WriteString(err.SpecRef)
|
||||||
|
needSep = true
|
||||||
|
}
|
||||||
|
if len(err.SpecText) > 0 {
|
||||||
|
if needSep {
|
||||||
|
if len(err.SpecRef) > 0 {
|
||||||
|
msg.WriteString(", ")
|
||||||
|
} else {
|
||||||
|
msg.WriteString(": ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.WriteString("'")
|
||||||
|
msg.WriteString(err.SpecText)
|
||||||
|
msg.WriteString("'")
|
||||||
|
}
|
||||||
|
msg.WriteString(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCategory indicates the category of an x509.Error.
|
||||||
|
type ErrCategory int
|
||||||
|
|
||||||
|
// ErrCategory values.
|
||||||
|
const (
|
||||||
|
UnknownCategory ErrCategory = iota
|
||||||
|
// Errors in ASN.1 encoding
|
||||||
|
InvalidASN1Encoding
|
||||||
|
InvalidASN1Content
|
||||||
|
InvalidASN1DER
|
||||||
|
// Errors in ASN.1 relative to schema
|
||||||
|
InvalidValueRange
|
||||||
|
InvalidASN1Type
|
||||||
|
UnexpectedAdditionalData
|
||||||
|
// Errors in X.509
|
||||||
|
PoorlyFormedCertificate // Fails a SHOULD clause
|
||||||
|
MalformedCertificate // Fails a MUST clause
|
||||||
|
PoorlyFormedCRL // Fails a SHOULD clause
|
||||||
|
MalformedCRL // Fails a MUST clause
|
||||||
|
// Errors relative to CA/Browser Forum guidelines
|
||||||
|
BaselineRequirementsFailure
|
||||||
|
EVRequirementsFailure
|
||||||
|
// Other errors
|
||||||
|
InsecureAlgorithm
|
||||||
|
UnrecognizedValue
|
||||||
|
)
|
||||||
|
|
||||||
|
func (category ErrCategory) String() string {
|
||||||
|
switch category {
|
||||||
|
case InvalidASN1Encoding:
|
||||||
|
return "Invalid ASN.1 encoding"
|
||||||
|
case InvalidASN1Content:
|
||||||
|
return "Invalid ASN.1 content"
|
||||||
|
case InvalidASN1DER:
|
||||||
|
return "Invalid ASN.1 distinguished encoding"
|
||||||
|
case InvalidValueRange:
|
||||||
|
return "Invalid value for range given in schema"
|
||||||
|
case InvalidASN1Type:
|
||||||
|
return "Invalid ASN.1 type for schema"
|
||||||
|
case UnexpectedAdditionalData:
|
||||||
|
return "Unexpected additional data present"
|
||||||
|
case PoorlyFormedCertificate:
|
||||||
|
return "Certificate does not comply with SHOULD clause in spec"
|
||||||
|
case MalformedCertificate:
|
||||||
|
return "Certificate does not comply with MUST clause in spec"
|
||||||
|
case PoorlyFormedCRL:
|
||||||
|
return "Certificate Revocation List does not comply with SHOULD clause in spec"
|
||||||
|
case MalformedCRL:
|
||||||
|
return "Certificate Revocation List does not comply with MUST clause in spec"
|
||||||
|
case BaselineRequirementsFailure:
|
||||||
|
return "Certificate does not comply with CA/BF baseline requirements"
|
||||||
|
case EVRequirementsFailure:
|
||||||
|
return "Certificate does not comply with CA/BF EV requirements"
|
||||||
|
case InsecureAlgorithm:
|
||||||
|
return "Certificate uses an insecure algorithm"
|
||||||
|
case UnrecognizedValue:
|
||||||
|
return "Certificate uses an unrecognized value"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown (%d)", category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorID is an identifier for an x509.Error, to allow filtering.
|
||||||
|
type ErrorID int
|
||||||
|
|
||||||
|
// Errors implements the error interface and holds a collection of errors found in a certificate or CRL.
|
||||||
|
type Errors struct {
|
||||||
|
Errs []Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error converts to a string.
|
||||||
|
func (e *Errors) Error() string {
|
||||||
|
return e.combineErrors(Error.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerboseError creates a more verbose error string, including spec details.
|
||||||
|
func (e *Errors) VerboseError() string {
|
||||||
|
return e.combineErrors(Error.VerboseError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal indicates whether e includes a fatal error
|
||||||
|
func (e *Errors) Fatal() bool {
|
||||||
|
return (e.FirstFatal() != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty indicates whether e has no errors.
|
||||||
|
func (e *Errors) Empty() bool {
|
||||||
|
return len(e.Errs) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstFatal returns the first fatal error in e, or nil
|
||||||
|
// if there is no fatal error.
|
||||||
|
func (e *Errors) FirstFatal() error {
|
||||||
|
for _, err := range e.Errs {
|
||||||
|
if err.Fatal {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddID adds the Error identified by the given id to an x509.Errors.
|
||||||
|
func (e *Errors) AddID(id ErrorID, args ...interface{}) {
|
||||||
|
e.Errs = append(e.Errs, NewError(id, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Errors) combineErrors(errfn func(Error) string) string {
|
||||||
|
if len(e.Errs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(e.Errs) == 1 {
|
||||||
|
return errfn((e.Errs)[0])
|
||||||
|
}
|
||||||
|
var msg bytes.Buffer
|
||||||
|
msg.WriteString("Errors:")
|
||||||
|
for _, err := range e.Errs {
|
||||||
|
msg.WriteString("\n ")
|
||||||
|
msg.WriteString(errfn(err))
|
||||||
|
}
|
||||||
|
return msg.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter creates a new Errors object with any entries from the filtered
|
||||||
|
// list of IDs removed.
|
||||||
|
func (e Errors) Filter(filtered []ErrorID) Errors {
|
||||||
|
var results Errors
|
||||||
|
eloop:
|
||||||
|
for _, v := range e.Errs {
|
||||||
|
for _, f := range filtered {
|
||||||
|
if v.ID == f {
|
||||||
|
break eloop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results.Errs = append(results.Errs, v)
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorFilter builds a list of error IDs (suitable for use with Errors.Filter) from a comma-separated string.
|
||||||
|
func ErrorFilter(ignore string) []ErrorID {
|
||||||
|
var ids []ErrorID
|
||||||
|
filters := strings.Split(ignore, ",")
|
||||||
|
for _, f := range filters {
|
||||||
|
v, err := strconv.Atoi(f)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ids = append(ids, ErrorID(v))
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
302
vendor/github.com/google/certificate-transparency-go/x509/errors.go
generated
vendored
Normal file
302
vendor/github.com/google/certificate-transparency-go/x509/errors.go
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
package x509
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// To preserve error IDs, only append to this list, never insert.
|
||||||
|
const (
|
||||||
|
ErrInvalidID ErrorID = iota
|
||||||
|
ErrInvalidCertList
|
||||||
|
ErrTrailingCertList
|
||||||
|
ErrUnexpectedlyCriticalCertListExtension
|
||||||
|
ErrUnexpectedlyNonCriticalCertListExtension
|
||||||
|
ErrInvalidCertListAuthKeyID
|
||||||
|
ErrTrailingCertListAuthKeyID
|
||||||
|
ErrInvalidCertListIssuerAltName
|
||||||
|
ErrInvalidCertListCRLNumber
|
||||||
|
ErrTrailingCertListCRLNumber
|
||||||
|
ErrNegativeCertListCRLNumber
|
||||||
|
ErrInvalidCertListDeltaCRL
|
||||||
|
ErrTrailingCertListDeltaCRL
|
||||||
|
ErrNegativeCertListDeltaCRL
|
||||||
|
ErrInvalidCertListIssuingDP
|
||||||
|
ErrTrailingCertListIssuingDP
|
||||||
|
ErrCertListIssuingDPMultipleTypes
|
||||||
|
ErrCertListIssuingDPInvalidFullName
|
||||||
|
ErrInvalidCertListFreshestCRL
|
||||||
|
ErrInvalidCertListAuthInfoAccess
|
||||||
|
ErrTrailingCertListAuthInfoAccess
|
||||||
|
ErrUnhandledCriticalCertListExtension
|
||||||
|
ErrUnexpectedlyCriticalRevokedCertExtension
|
||||||
|
ErrUnexpectedlyNonCriticalRevokedCertExtension
|
||||||
|
ErrInvalidRevocationReason
|
||||||
|
ErrTrailingRevocationReason
|
||||||
|
ErrInvalidRevocationInvalidityDate
|
||||||
|
ErrTrailingRevocationInvalidityDate
|
||||||
|
ErrInvalidRevocationIssuer
|
||||||
|
ErrUnhandledCriticalRevokedCertExtension
|
||||||
|
|
||||||
|
ErrMaxID
|
||||||
|
)
|
||||||
|
|
||||||
|
// idToError gives a template x509.Error for each defined ErrorID; where the Summary
|
||||||
|
// field may hold format specifiers that take field parameters.
|
||||||
|
var idToError map[ErrorID]Error
|
||||||
|
|
||||||
|
var errorInfo = []Error{
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertList,
|
||||||
|
Summary: "x509: failed to parse CertificateList: %v",
|
||||||
|
Field: "CertificateList",
|
||||||
|
SpecRef: "RFC 5280 s5.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertList,
|
||||||
|
Summary: "x509: trailing data after CertificateList",
|
||||||
|
Field: "CertificateList",
|
||||||
|
SpecRef: "RFC 5280 s5.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ID: ErrUnexpectedlyCriticalCertListExtension,
|
||||||
|
Summary: "x509: certificate list extension %v marked critical but expected to be non-critical",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.critical",
|
||||||
|
SpecRef: "RFC 5280 s5.2",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrUnexpectedlyNonCriticalCertListExtension,
|
||||||
|
Summary: "x509: certificate list extension %v marked non-critical but expected to be critical",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.critical",
|
||||||
|
SpecRef: "RFC 5280 s5.2",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListAuthKeyID,
|
||||||
|
Summary: "x509: failed to unmarshal certificate-list authority key-id: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.AuthorityKeyIdentifier",
|
||||||
|
SpecRef: "RFC 5280 s5.2.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertListAuthKeyID,
|
||||||
|
Summary: "x509: trailing data after certificate list auth key ID",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.AuthorityKeyIdentifier",
|
||||||
|
SpecRef: "RFC 5280 s5.2.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListIssuerAltName,
|
||||||
|
Summary: "x509: failed to parse CRL issuer alt name: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.IssuerAltName",
|
||||||
|
SpecRef: "RFC 5280 s5.2.2",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListCRLNumber,
|
||||||
|
Summary: "x509: failed to unmarshal certificate-list crl-number: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.CRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.3",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertListCRLNumber,
|
||||||
|
Summary: "x509: trailing data after certificate list crl-number",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.CRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.3",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrNegativeCertListCRLNumber,
|
||||||
|
Summary: "x509: negative certificate list crl-number: %d",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.CRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.3",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListDeltaCRL,
|
||||||
|
Summary: "x509: failed to unmarshal certificate-list delta-crl: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.BaseCRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.4",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertListDeltaCRL,
|
||||||
|
Summary: "x509: trailing data after certificate list delta-crl",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.BaseCRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.4",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrNegativeCertListDeltaCRL,
|
||||||
|
Summary: "x509: negative certificate list base-crl-number: %d",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.BaseCRLNumber",
|
||||||
|
SpecRef: "RFC 5280 s5.2.4",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListIssuingDP,
|
||||||
|
Summary: "x509: failed to unmarshal certificate list issuing distribution point: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint",
|
||||||
|
SpecRef: "RFC 5280 s5.2.5",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertListIssuingDP,
|
||||||
|
Summary: "x509: trailing data after certificate list issuing distribution point",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint",
|
||||||
|
SpecRef: "RFC 5280 s5.2.5",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrCertListIssuingDPMultipleTypes,
|
||||||
|
Summary: "x509: multiple cert types set in issuing-distribution-point: user:%v CA:%v attr:%v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint",
|
||||||
|
SpecRef: "RFC 5280 s5.2.5",
|
||||||
|
SpecText: "at most one of onlyContainsUserCerts, onlyContainsCACerts, and onlyContainsAttributeCerts may be set to TRUE.",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrCertListIssuingDPInvalidFullName,
|
||||||
|
Summary: "x509: failed to parse CRL issuing-distribution-point fullName: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.IssuingDistributionPoint.distributionPoint",
|
||||||
|
SpecRef: "RFC 5280 s5.2.5",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListFreshestCRL,
|
||||||
|
Summary: "x509: failed to unmarshal certificate list freshestCRL: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.FreshestCRL",
|
||||||
|
SpecRef: "RFC 5280 s5.2.6",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidCertListAuthInfoAccess,
|
||||||
|
Summary: "x509: failed to unmarshal certificate list authority info access: %v",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.AuthorityInfoAccess",
|
||||||
|
SpecRef: "RFC 5280 s5.2.7",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingCertListAuthInfoAccess,
|
||||||
|
Summary: "x509: trailing data after certificate list authority info access",
|
||||||
|
Field: "tbsCertList.crlExtensions.*.AuthorityInfoAccess",
|
||||||
|
SpecRef: "RFC 5280 s5.2.7",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrUnhandledCriticalCertListExtension,
|
||||||
|
Summary: "x509: unhandled critical extension in certificate list: %v",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlExtensions.*",
|
||||||
|
SpecRef: "RFC 5280 s5.2",
|
||||||
|
SpecText: "If a CRL contains a critical extension that the application cannot process, then the application MUST NOT use that CRL to determine the status of certificates.",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ID: ErrUnexpectedlyCriticalRevokedCertExtension,
|
||||||
|
Summary: "x509: revoked certificate extension %v marked critical but expected to be non-critical",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.critical",
|
||||||
|
SpecRef: "RFC 5280 s5.3",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrUnexpectedlyNonCriticalRevokedCertExtension,
|
||||||
|
Summary: "x509: revoked certificate extension %v marked non-critical but expected to be critical",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.critical",
|
||||||
|
SpecRef: "RFC 5280 s5.3",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ID: ErrInvalidRevocationReason,
|
||||||
|
Summary: "x509: failed to parse revocation reason: %v",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CRLReason",
|
||||||
|
SpecRef: "RFC 5280 s5.3.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingRevocationReason,
|
||||||
|
Summary: "x509: trailing data after revoked certificate reason",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CRLReason",
|
||||||
|
SpecRef: "RFC 5280 s5.3.1",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidRevocationInvalidityDate,
|
||||||
|
Summary: "x509: failed to parse revoked certificate invalidity date: %v",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.InvalidityDate",
|
||||||
|
SpecRef: "RFC 5280 s5.3.2",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrTrailingRevocationInvalidityDate,
|
||||||
|
Summary: "x509: trailing data after revoked certificate invalidity date",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.InvalidityDate",
|
||||||
|
SpecRef: "RFC 5280 s5.3.2",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrInvalidRevocationIssuer,
|
||||||
|
Summary: "x509: failed to parse revocation issuer %v",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*.CertificateIssuer",
|
||||||
|
SpecRef: "RFC 5280 s5.3.3",
|
||||||
|
Category: InvalidASN1Content,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: ErrUnhandledCriticalRevokedCertExtension,
|
||||||
|
Summary: "x509: unhandled critical extension in revoked certificate: %v",
|
||||||
|
Field: "tbsCertList.revokedCertificates.crlEntryExtensions.*",
|
||||||
|
SpecRef: "RFC 5280 s5.3",
|
||||||
|
SpecText: "If a CRL contains a critical CRL entry extension that the application cannot process, then the application MUST NOT use that CRL to determine the status of any certificates.",
|
||||||
|
Category: MalformedCRL,
|
||||||
|
Fatal: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
idToError = make(map[ErrorID]Error, len(errorInfo))
|
||||||
|
for _, info := range errorInfo {
|
||||||
|
idToError[info.ID] = info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewError builds a new x509.Error based on the template for the given id.
|
||||||
|
func NewError(id ErrorID, args ...interface{}) Error {
|
||||||
|
var err Error
|
||||||
|
if id >= ErrMaxID {
|
||||||
|
err.ID = id
|
||||||
|
err.Summary = fmt.Sprintf("Unknown error ID %v: args %+v", id, args)
|
||||||
|
err.Fatal = true
|
||||||
|
} else {
|
||||||
|
err = idToError[id]
|
||||||
|
err.Summary = fmt.Sprintf(err.Summary, args...)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
164
vendor/github.com/google/certificate-transparency-go/x509/names.go
generated
vendored
Normal file
164
vendor/github.com/google/certificate-transparency-go/x509/names.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// 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 LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
|
"github.com/google/certificate-transparency-go/x509/pkix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GeneralName tag values from RFC 5280, 4.2.1.6
|
||||||
|
tagOtherName = 0
|
||||||
|
tagRFC822Name = 1
|
||||||
|
tagDNSName = 2
|
||||||
|
tagX400Address = 3
|
||||||
|
tagDirectoryName = 4
|
||||||
|
tagEDIPartyName = 5
|
||||||
|
tagURI = 6
|
||||||
|
tagIPAddress = 7
|
||||||
|
tagRegisteredID = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// OtherName describes a name related to a certificate which is not in one
|
||||||
|
// of the standard name formats. RFC 5280, 4.2.1.6:
|
||||||
|
// OtherName ::= SEQUENCE {
|
||||||
|
// type-id OBJECT IDENTIFIER,
|
||||||
|
// value [0] EXPLICIT ANY DEFINED BY type-id }
|
||||||
|
type OtherName struct {
|
||||||
|
TypeID asn1.ObjectIdentifier
|
||||||
|
Value asn1.RawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneralNames holds a collection of names related to a certificate.
|
||||||
|
type GeneralNames struct {
|
||||||
|
DNSNames []string
|
||||||
|
EmailAddresses []string
|
||||||
|
DirectoryNames []pkix.Name
|
||||||
|
URIs []string
|
||||||
|
IPNets []net.IPNet
|
||||||
|
RegisteredIDs []asn1.ObjectIdentifier
|
||||||
|
OtherNames []OtherName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the total number of names in a GeneralNames object.
|
||||||
|
func (gn GeneralNames) Len() int {
|
||||||
|
return (len(gn.DNSNames) + len(gn.EmailAddresses) + len(gn.DirectoryNames) +
|
||||||
|
len(gn.URIs) + len(gn.IPNets) + len(gn.RegisteredIDs) + len(gn.OtherNames))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty indicates whether a GeneralNames object is empty.
|
||||||
|
func (gn GeneralNames) Empty() bool {
|
||||||
|
return gn.Len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGeneralNames(value []byte, gname *GeneralNames) error {
|
||||||
|
// RFC 5280, 4.2.1.6
|
||||||
|
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
|
||||||
|
//
|
||||||
|
// GeneralName ::= CHOICE {
|
||||||
|
// otherName [0] OtherName,
|
||||||
|
// rfc822Name [1] IA5String,
|
||||||
|
// dNSName [2] IA5String,
|
||||||
|
// x400Address [3] ORAddress,
|
||||||
|
// directoryName [4] Name,
|
||||||
|
// ediPartyName [5] EDIPartyName,
|
||||||
|
// uniformResourceIdentifier [6] IA5String,
|
||||||
|
// iPAddress [7] OCTET STRING,
|
||||||
|
// registeredID [8] OBJECT IDENTIFIER }
|
||||||
|
var seq asn1.RawValue
|
||||||
|
var rest []byte
|
||||||
|
if rest, err := asn1.Unmarshal(value, &seq); err != nil {
|
||||||
|
return fmt.Errorf("x509: failed to parse GeneralNames: %v", err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
return fmt.Errorf("x509: trailing data after GeneralNames")
|
||||||
|
}
|
||||||
|
if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal {
|
||||||
|
return fmt.Errorf("x509: failed to parse GeneralNames sequence, tag %+v", seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
rest = seq.Bytes
|
||||||
|
for len(rest) > 0 {
|
||||||
|
var err error
|
||||||
|
rest, err = parseGeneralName(rest, gname, false)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("x509: failed to parse GeneralName: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGeneralName(data []byte, gname *GeneralNames, withMask bool) ([]byte, error) {
|
||||||
|
var v asn1.RawValue
|
||||||
|
var rest []byte
|
||||||
|
var err error
|
||||||
|
rest, err = asn1.Unmarshal(data, &v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames: %v", err)
|
||||||
|
}
|
||||||
|
switch v.Tag {
|
||||||
|
case tagOtherName:
|
||||||
|
if !v.IsCompound {
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: not compound")
|
||||||
|
}
|
||||||
|
var other OtherName
|
||||||
|
v.FullBytes = append([]byte{}, v.FullBytes...)
|
||||||
|
v.FullBytes[0] = asn1.TagSequence | 0x20
|
||||||
|
_, err = asn1.Unmarshal(v.FullBytes, &other)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: %v", err)
|
||||||
|
}
|
||||||
|
gname.OtherNames = append(gname.OtherNames, other)
|
||||||
|
case tagRFC822Name:
|
||||||
|
gname.EmailAddresses = append(gname.EmailAddresses, string(v.Bytes))
|
||||||
|
case tagDNSName:
|
||||||
|
dns := string(v.Bytes)
|
||||||
|
gname.DNSNames = append(gname.DNSNames, dns)
|
||||||
|
case tagDirectoryName:
|
||||||
|
var rdnSeq pkix.RDNSequence
|
||||||
|
if _, err := asn1.Unmarshal(v.Bytes, &rdnSeq); err != nil {
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.directoryName: %v", err)
|
||||||
|
}
|
||||||
|
var dirName pkix.Name
|
||||||
|
dirName.FillFromRDNSequence(&rdnSeq)
|
||||||
|
gname.DirectoryNames = append(gname.DirectoryNames, dirName)
|
||||||
|
case tagURI:
|
||||||
|
gname.URIs = append(gname.URIs, string(v.Bytes))
|
||||||
|
case tagIPAddress:
|
||||||
|
vlen := len(v.Bytes)
|
||||||
|
if withMask {
|
||||||
|
switch vlen {
|
||||||
|
case (2 * net.IPv4len), (2 * net.IPv6len):
|
||||||
|
ipNet := net.IPNet{IP: v.Bytes[0 : vlen/2], Mask: v.Bytes[vlen/2:]}
|
||||||
|
gname.IPNets = append(gname.IPNets, ipNet)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("x509: invalid IP/mask length %d in GeneralNames.iPAddress", vlen)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch vlen {
|
||||||
|
case net.IPv4len, net.IPv6len:
|
||||||
|
ipNet := net.IPNet{IP: v.Bytes}
|
||||||
|
gname.IPNets = append(gname.IPNets, ipNet)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("x509: invalid IP length %d in GeneralNames.iPAddress", vlen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case tagRegisteredID:
|
||||||
|
var oid asn1.ObjectIdentifier
|
||||||
|
v.FullBytes = append([]byte{}, v.FullBytes...)
|
||||||
|
v.FullBytes[0] = asn1.TagOID
|
||||||
|
_, err = asn1.Unmarshal(v.FullBytes, &oid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.registeredID: %v", err)
|
||||||
|
}
|
||||||
|
gname.RegisteredIDs = append(gname.RegisteredIDs, oid)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("x509: failed to unmarshal GeneralName: unknown tag %d", v.Tag)
|
||||||
|
}
|
||||||
|
return rest, nil
|
||||||
|
}
|
||||||
26
vendor/github.com/google/certificate-transparency-go/x509/nilref_nil_darwin.go
generated
vendored
Normal file
26
vendor/github.com/google/certificate-transparency-go/x509/nilref_nil_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo,!arm,!arm64,!ios,!go1.10
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
|
||||||
|
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// For Go versions before 1.10, nil values for Apple's CoreFoundation
|
||||||
|
// CF*Ref types were represented by nil. See:
|
||||||
|
// https://github.com/golang/go/commit/b868616b63a8
|
||||||
|
func setNilCFRef(v *C.CFDataRef) {
|
||||||
|
*v = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNilCFRef(v C.CFDataRef) bool {
|
||||||
|
return v == nil
|
||||||
|
}
|
||||||
26
vendor/github.com/google/certificate-transparency-go/x509/nilref_zero_darwin.go
generated
vendored
Normal file
26
vendor/github.com/google/certificate-transparency-go/x509/nilref_zero_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo,!arm,!arm64,!ios,go1.10
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
|
||||||
|
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// For Go versions >= 1.10, nil values for Apple's CoreFoundation
|
||||||
|
// CF*Ref types are represented by zero. See:
|
||||||
|
// https://github.com/golang/go/commit/b868616b63a8
|
||||||
|
func setNilCFRef(v *C.CFDataRef) {
|
||||||
|
*v = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNilCFRef(v C.CFDataRef) bool {
|
||||||
|
return v == 0
|
||||||
|
}
|
||||||
9
vendor/github.com/google/certificate-transparency/go/x509/pem_decrypt.go → vendor/github.com/google/certificate-transparency-go/x509/pem_decrypt.go
generated
vendored
Executable file → Normal file
9
vendor/github.com/google/certificate-transparency/go/x509/pem_decrypt.go → vendor/github.com/google/certificate-transparency-go/x509/pem_decrypt.go
generated
vendored
Executable file → Normal file
@@ -108,7 +108,10 @@ var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
|
|||||||
// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
|
// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
|
||||||
// the DEK-Info header to determine the algorithm used for decryption. If no
|
// the DEK-Info header to determine the algorithm used for decryption. If no
|
||||||
// DEK-Info header is present, an error is returned. If an incorrect password
|
// DEK-Info header is present, an error is returned. If an incorrect password
|
||||||
// is detected an IncorrectPasswordError is returned.
|
// is detected an IncorrectPasswordError is returned. Because of deficiencies
|
||||||
|
// in the encrypted-PEM format, it's not always possible to detect an incorrect
|
||||||
|
// password. In these cases no error will be returned but the decrypted DER
|
||||||
|
// bytes will be random noise.
|
||||||
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
|
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
|
||||||
dek, ok := b.Headers["DEK-Info"]
|
dek, ok := b.Headers["DEK-Info"]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -141,6 +144,10 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(b.Bytes)%block.BlockSize() != 0 {
|
||||||
|
return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size")
|
||||||
|
}
|
||||||
|
|
||||||
data := make([]byte, len(b.Bytes))
|
data := make([]byte, len(b.Bytes))
|
||||||
dec := cipher.NewCBCDecrypter(block, iv)
|
dec := cipher.NewCBCDecrypter(block, iv)
|
||||||
dec.CryptBlocks(data, b.Bytes)
|
dec.CryptBlocks(data, b.Bytes)
|
||||||
57
vendor/github.com/google/certificate-transparency/go/x509/pkcs1.go → vendor/github.com/google/certificate-transparency-go/x509/pkcs1.go
generated
vendored
Executable file → Normal file
57
vendor/github.com/google/certificate-transparency/go/x509/pkcs1.go → vendor/github.com/google/certificate-transparency-go/x509/pkcs1.go
generated
vendored
Executable file → Normal file
@@ -6,11 +6,10 @@ package x509
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
// START CT CHANGES
|
|
||||||
"github.com/google/certificate-transparency/go/asn1"
|
|
||||||
// END CT CHANGES
|
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
||||||
@@ -37,16 +36,21 @@ type pkcs1AdditionalRSAPrime struct {
|
|||||||
Coeff *big.Int
|
Coeff *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key.
|
||||||
|
type pkcs1PublicKey struct {
|
||||||
|
N *big.Int
|
||||||
|
E int
|
||||||
|
}
|
||||||
|
|
||||||
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
||||||
func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
|
func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
|
||||||
var priv pkcs1PrivateKey
|
var priv pkcs1PrivateKey
|
||||||
rest, err := asn1.Unmarshal(der, &priv)
|
rest, err := asn1.Unmarshal(der, &priv)
|
||||||
if len(rest) > 0 {
|
if len(rest) > 0 {
|
||||||
err = asn1.SyntaxError{Msg: "trailing data"}
|
return nil, asn1.SyntaxError{Msg: "trailing data"}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if priv.Version > 1 {
|
if priv.Version > 1 {
|
||||||
@@ -57,7 +61,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
|
|||||||
return nil, errors.New("x509: private key contains zero or negative value")
|
return nil, errors.New("x509: private key contains zero or negative value")
|
||||||
}
|
}
|
||||||
|
|
||||||
key = new(rsa.PrivateKey)
|
key := new(rsa.PrivateKey)
|
||||||
key.PublicKey = rsa.PublicKey{
|
key.PublicKey = rsa.PublicKey{
|
||||||
E: priv.E,
|
E: priv.E,
|
||||||
N: priv.N,
|
N: priv.N,
|
||||||
@@ -82,7 +86,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
|
|||||||
}
|
}
|
||||||
key.Precompute()
|
key.Precompute()
|
||||||
|
|
||||||
return
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
||||||
@@ -117,8 +121,35 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
|
// ParsePKCS1PublicKey parses a PKCS#1 public key in ASN.1 DER form.
|
||||||
type rsaPublicKey struct {
|
func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) {
|
||||||
N *big.Int
|
var pub pkcs1PublicKey
|
||||||
E int
|
rest, err := asn1.Unmarshal(der, &pub)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(rest) > 0 {
|
||||||
|
return nil, asn1.SyntaxError{Msg: "trailing data"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pub.N.Sign() <= 0 || pub.E <= 0 {
|
||||||
|
return nil, errors.New("x509: public key contains zero or negative value")
|
||||||
|
}
|
||||||
|
if pub.E > 1<<31-1 {
|
||||||
|
return nil, errors.New("x509: public key contains large public exponent")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rsa.PublicKey{
|
||||||
|
E: pub.E,
|
||||||
|
N: pub.N,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalPKCS1PublicKey converts an RSA public key to PKCS#1, ASN.1 DER form.
|
||||||
|
func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte {
|
||||||
|
derBytes, _ := asn1.Marshal(pkcs1PublicKey{
|
||||||
|
N: key.N,
|
||||||
|
E: key.E,
|
||||||
|
})
|
||||||
|
return derBytes
|
||||||
}
|
}
|
||||||
102
vendor/github.com/google/certificate-transparency-go/x509/pkcs8.go
generated
vendored
Normal file
102
vendor/github.com/google/certificate-transparency-go/x509/pkcs8.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
|
"github.com/google/certificate-transparency-go/x509/pkix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
|
||||||
|
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
|
||||||
|
// and RFC 5208.
|
||||||
|
type pkcs8 struct {
|
||||||
|
Version int
|
||||||
|
Algo pkix.AlgorithmIdentifier
|
||||||
|
PrivateKey []byte
|
||||||
|
// optional attributes omitted.
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key.
|
||||||
|
// See RFC 5208.
|
||||||
|
func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
|
||||||
|
var privKey pkcs8
|
||||||
|
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case privKey.Algo.Algorithm.Equal(OIDPublicKeyRSA):
|
||||||
|
key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
|
||||||
|
case privKey.Algo.Algorithm.Equal(OIDPublicKeyECDSA):
|
||||||
|
bytes := privKey.Algo.Parameters.FullBytes
|
||||||
|
namedCurveOID := new(asn1.ObjectIdentifier)
|
||||||
|
if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
|
||||||
|
namedCurveOID = nil
|
||||||
|
}
|
||||||
|
key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form.
|
||||||
|
// The following key types are supported: *rsa.PrivateKey, *ecdsa.PublicKey.
|
||||||
|
// Unsupported key types result in an error.
|
||||||
|
//
|
||||||
|
// See RFC 5208.
|
||||||
|
func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) {
|
||||||
|
var privKey pkcs8
|
||||||
|
|
||||||
|
switch k := key.(type) {
|
||||||
|
case *rsa.PrivateKey:
|
||||||
|
privKey.Algo = pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: OIDPublicKeyRSA,
|
||||||
|
Parameters: asn1.NullRawValue,
|
||||||
|
}
|
||||||
|
privKey.PrivateKey = MarshalPKCS1PrivateKey(k)
|
||||||
|
|
||||||
|
case *ecdsa.PrivateKey:
|
||||||
|
oid, ok := OIDFromNamedCurve(k.Curve)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("x509: unknown curve while marshalling to PKCS#8")
|
||||||
|
}
|
||||||
|
|
||||||
|
oidBytes, err := asn1.Marshal(oid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey.Algo = pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: OIDPublicKeyECDSA,
|
||||||
|
Parameters: asn1.RawValue{
|
||||||
|
FullBytes: oidBytes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil {
|
||||||
|
return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("x509: unknown key type while marshalling PKCS#8: %T", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return asn1.Marshal(privKey)
|
||||||
|
}
|
||||||
@@ -3,9 +3,9 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["pkix.go"],
|
srcs = ["pkix.go"],
|
||||||
importpath = "github.com/google/certificate-transparency/go/x509/pkix",
|
importpath = "github.com/google/certificate-transparency-go/x509/pkix",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = ["//vendor/github.com/google/certificate-transparency/go/asn1:go_default_library"],
|
deps = ["//vendor/github.com/google/certificate-transparency-go/asn1:go_default_library"],
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
288
vendor/github.com/google/certificate-transparency-go/x509/pkix/pkix.go
generated
vendored
Normal file
288
vendor/github.com/google/certificate-transparency-go/x509/pkix/pkix.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package pkix contains shared, low level structures used for ASN.1 parsing
|
||||||
|
// and serialization of X.509 certificates, CRL and OCSP.
|
||||||
|
package pkix
|
||||||
|
|
||||||
|
import (
|
||||||
|
// START CT CHANGES
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
|
// END CT CHANGES
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
||||||
|
// 5280, section 4.1.1.2.
|
||||||
|
type AlgorithmIdentifier struct {
|
||||||
|
Algorithm asn1.ObjectIdentifier
|
||||||
|
Parameters asn1.RawValue `asn1:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RDNSequence []RelativeDistinguishedNameSET
|
||||||
|
|
||||||
|
var attributeTypeNames = map[string]string{
|
||||||
|
"2.5.4.6": "C",
|
||||||
|
"2.5.4.10": "O",
|
||||||
|
"2.5.4.11": "OU",
|
||||||
|
"2.5.4.3": "CN",
|
||||||
|
"2.5.4.5": "SERIALNUMBER",
|
||||||
|
"2.5.4.7": "L",
|
||||||
|
"2.5.4.8": "ST",
|
||||||
|
"2.5.4.9": "STREET",
|
||||||
|
"2.5.4.17": "POSTALCODE",
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the sequence r,
|
||||||
|
// roughly following the RFC 2253 Distinguished Names syntax.
|
||||||
|
func (r RDNSequence) String() string {
|
||||||
|
s := ""
|
||||||
|
for i := 0; i < len(r); i++ {
|
||||||
|
rdn := r[len(r)-1-i]
|
||||||
|
if i > 0 {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
for j, tv := range rdn {
|
||||||
|
if j > 0 {
|
||||||
|
s += "+"
|
||||||
|
}
|
||||||
|
|
||||||
|
oidString := tv.Type.String()
|
||||||
|
typeName, ok := attributeTypeNames[oidString]
|
||||||
|
if !ok {
|
||||||
|
derBytes, err := asn1.Marshal(tv.Value)
|
||||||
|
if err == nil {
|
||||||
|
s += oidString + "=#" + hex.EncodeToString(derBytes)
|
||||||
|
continue // No value escaping necessary.
|
||||||
|
}
|
||||||
|
|
||||||
|
typeName = oidString
|
||||||
|
}
|
||||||
|
|
||||||
|
valueString := fmt.Sprint(tv.Value)
|
||||||
|
escaped := make([]rune, 0, len(valueString))
|
||||||
|
|
||||||
|
for k, c := range valueString {
|
||||||
|
escape := false
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case ',', '+', '"', '\\', '<', '>', ';':
|
||||||
|
escape = true
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
escape = k == 0 || k == len(valueString)-1
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
escape = k == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if escape {
|
||||||
|
escaped = append(escaped, '\\', c)
|
||||||
|
} else {
|
||||||
|
escaped = append(escaped, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s += typeName + "=" + string(escaped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type RelativeDistinguishedNameSET []AttributeTypeAndValue
|
||||||
|
|
||||||
|
// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
|
||||||
|
// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
|
||||||
|
type AttributeTypeAndValue struct {
|
||||||
|
Type asn1.ObjectIdentifier
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
|
||||||
|
// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
|
||||||
|
type AttributeTypeAndValueSET struct {
|
||||||
|
Type asn1.ObjectIdentifier
|
||||||
|
Value [][]AttributeTypeAndValue `asn1:"set"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extension represents the ASN.1 structure of the same name. See RFC
|
||||||
|
// 5280, section 4.2.
|
||||||
|
type Extension struct {
|
||||||
|
Id asn1.ObjectIdentifier
|
||||||
|
Critical bool `asn1:"optional"`
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name represents an X.509 distinguished name. This only includes the common
|
||||||
|
// elements of a DN. When parsing, all elements are stored in Names and
|
||||||
|
// non-standard elements can be extracted from there. When marshaling, elements
|
||||||
|
// in ExtraNames are appended and override other values with the same OID.
|
||||||
|
type Name struct {
|
||||||
|
Country, Organization, OrganizationalUnit []string
|
||||||
|
Locality, Province []string
|
||||||
|
StreetAddress, PostalCode []string
|
||||||
|
SerialNumber, CommonName string
|
||||||
|
|
||||||
|
Names []AttributeTypeAndValue
|
||||||
|
ExtraNames []AttributeTypeAndValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
|
||||||
|
for _, rdn := range *rdns {
|
||||||
|
if len(rdn) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, atv := range rdn {
|
||||||
|
n.Names = append(n.Names, atv)
|
||||||
|
value, ok := atv.Value.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t := atv.Type
|
||||||
|
if len(t) == 4 && t[0] == OIDAttribute[0] && t[1] == OIDAttribute[1] && t[2] == OIDAttribute[2] {
|
||||||
|
switch t[3] {
|
||||||
|
case OIDCommonName[3]:
|
||||||
|
n.CommonName = value
|
||||||
|
case OIDSerialNumber[3]:
|
||||||
|
n.SerialNumber = value
|
||||||
|
case OIDCountry[3]:
|
||||||
|
n.Country = append(n.Country, value)
|
||||||
|
case OIDLocality[3]:
|
||||||
|
n.Locality = append(n.Locality, value)
|
||||||
|
case OIDProvince[3]:
|
||||||
|
n.Province = append(n.Province, value)
|
||||||
|
case OIDStreetAddress[3]:
|
||||||
|
n.StreetAddress = append(n.StreetAddress, value)
|
||||||
|
case OIDOrganization[3]:
|
||||||
|
n.Organization = append(n.Organization, value)
|
||||||
|
case OIDOrganizationalUnit[3]:
|
||||||
|
n.OrganizationalUnit = append(n.OrganizationalUnit, value)
|
||||||
|
case OIDPostalCode[3]:
|
||||||
|
n.PostalCode = append(n.PostalCode, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
OIDAttribute = asn1.ObjectIdentifier{2, 5, 4}
|
||||||
|
OIDCountry = asn1.ObjectIdentifier{2, 5, 4, 6}
|
||||||
|
OIDOrganization = asn1.ObjectIdentifier{2, 5, 4, 10}
|
||||||
|
OIDOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11}
|
||||||
|
OIDCommonName = asn1.ObjectIdentifier{2, 5, 4, 3}
|
||||||
|
OIDSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5}
|
||||||
|
OIDLocality = asn1.ObjectIdentifier{2, 5, 4, 7}
|
||||||
|
OIDProvince = asn1.ObjectIdentifier{2, 5, 4, 8}
|
||||||
|
OIDStreetAddress = asn1.ObjectIdentifier{2, 5, 4, 9}
|
||||||
|
OIDPostalCode = asn1.ObjectIdentifier{2, 5, 4, 17}
|
||||||
|
|
||||||
|
OIDPseudonym = asn1.ObjectIdentifier{2, 5, 4, 65}
|
||||||
|
OIDTitle = asn1.ObjectIdentifier{2, 5, 4, 12}
|
||||||
|
OIDDnQualifier = asn1.ObjectIdentifier{2, 5, 4, 46}
|
||||||
|
OIDName = asn1.ObjectIdentifier{2, 5, 4, 41}
|
||||||
|
OIDSurname = asn1.ObjectIdentifier{2, 5, 4, 4}
|
||||||
|
OIDGivenName = asn1.ObjectIdentifier{2, 5, 4, 42}
|
||||||
|
OIDInitials = asn1.ObjectIdentifier{2, 5, 4, 43}
|
||||||
|
OIDGenerationQualifier = asn1.ObjectIdentifier{2, 5, 4, 44}
|
||||||
|
)
|
||||||
|
|
||||||
|
// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
|
||||||
|
// and returns the new value. The relativeDistinguishedNameSET contains an
|
||||||
|
// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
|
||||||
|
// search for AttributeTypeAndValue.
|
||||||
|
func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
|
||||||
|
if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
s := make([]AttributeTypeAndValue, len(values))
|
||||||
|
for i, value := range values {
|
||||||
|
s[i].Type = oid
|
||||||
|
s[i].Value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(in, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n Name) ToRDNSequence() (ret RDNSequence) {
|
||||||
|
ret = n.appendRDNs(ret, n.Country, OIDCountry)
|
||||||
|
ret = n.appendRDNs(ret, n.Province, OIDProvince)
|
||||||
|
ret = n.appendRDNs(ret, n.Locality, OIDLocality)
|
||||||
|
ret = n.appendRDNs(ret, n.StreetAddress, OIDStreetAddress)
|
||||||
|
ret = n.appendRDNs(ret, n.PostalCode, OIDPostalCode)
|
||||||
|
ret = n.appendRDNs(ret, n.Organization, OIDOrganization)
|
||||||
|
ret = n.appendRDNs(ret, n.OrganizationalUnit, OIDOrganizationalUnit)
|
||||||
|
if len(n.CommonName) > 0 {
|
||||||
|
ret = n.appendRDNs(ret, []string{n.CommonName}, OIDCommonName)
|
||||||
|
}
|
||||||
|
if len(n.SerialNumber) > 0 {
|
||||||
|
ret = n.appendRDNs(ret, []string{n.SerialNumber}, OIDSerialNumber)
|
||||||
|
}
|
||||||
|
for _, atv := range n.ExtraNames {
|
||||||
|
ret = append(ret, []AttributeTypeAndValue{atv})
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string form of n, roughly following
|
||||||
|
// the RFC 2253 Distinguished Names syntax.
|
||||||
|
func (n Name) String() string {
|
||||||
|
return n.ToRDNSequence().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// oidInAttributeTypeAndValue returns whether a type with the given OID exists
|
||||||
|
// in atv.
|
||||||
|
func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
|
||||||
|
for _, a := range atv {
|
||||||
|
if a.Type.Equal(oid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateList represents the ASN.1 structure of the same name. See RFC
|
||||||
|
// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
|
||||||
|
// signature.
|
||||||
|
type CertificateList struct {
|
||||||
|
TBSCertList TBSCertificateList
|
||||||
|
SignatureAlgorithm AlgorithmIdentifier
|
||||||
|
SignatureValue asn1.BitString
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasExpired reports whether certList should have been updated by now.
|
||||||
|
func (certList *CertificateList) HasExpired(now time.Time) bool {
|
||||||
|
return !now.Before(certList.TBSCertList.NextUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBSCertificateList represents the ASN.1 structure TBSCertList. See RFC
|
||||||
|
// 5280, section 5.1.
|
||||||
|
type TBSCertificateList struct {
|
||||||
|
Raw asn1.RawContent
|
||||||
|
Version int `asn1:"optional,default:0"`
|
||||||
|
Signature AlgorithmIdentifier
|
||||||
|
Issuer RDNSequence
|
||||||
|
ThisUpdate time.Time
|
||||||
|
NextUpdate time.Time `asn1:"optional"`
|
||||||
|
RevokedCertificates []RevokedCertificate `asn1:"optional"`
|
||||||
|
Extensions []Extension `asn1:"tag:0,optional,explicit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokedCertificate represents the unnamed ASN.1 structure that makes up the
|
||||||
|
// revokedCertificates member of the TBSCertList structure. See RFC
|
||||||
|
// 5280, section 5.1.
|
||||||
|
type RevokedCertificate struct {
|
||||||
|
SerialNumber *big.Int
|
||||||
|
RevocationTime time.Time
|
||||||
|
Extensions []Extension `asn1:"optional"`
|
||||||
|
}
|
||||||
362
vendor/github.com/google/certificate-transparency-go/x509/revoked.go
generated
vendored
Normal file
362
vendor/github.com/google/certificate-transparency-go/x509/revoked.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/pem"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
|
"github.com/google/certificate-transparency-go/x509/pkix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// OID values for CRL extensions (TBSCertList.Extensions), RFC 5280 s5.2.
|
||||||
|
OIDExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20}
|
||||||
|
OIDExtensionDeltaCRLIndicator = asn1.ObjectIdentifier{2, 5, 29, 27}
|
||||||
|
OIDExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28}
|
||||||
|
// OID values for CRL entry extensions (RevokedCertificate.Extensions), RFC 5280 s5.3
|
||||||
|
OIDExtensionCRLReasons = asn1.ObjectIdentifier{2, 5, 29, 21}
|
||||||
|
OIDExtensionInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24}
|
||||||
|
OIDExtensionCertificateIssuer = asn1.ObjectIdentifier{2, 5, 29, 29}
|
||||||
|
)
|
||||||
|
|
||||||
|
// RevocationReasonCode represents the reason for a certificate revocation; see RFC 5280 s5.3.1.
|
||||||
|
type RevocationReasonCode asn1.Enumerated
|
||||||
|
|
||||||
|
// RevocationReasonCode values.
|
||||||
|
var (
|
||||||
|
Unspecified = RevocationReasonCode(0)
|
||||||
|
KeyCompromise = RevocationReasonCode(1)
|
||||||
|
CACompromise = RevocationReasonCode(2)
|
||||||
|
AffiliationChanged = RevocationReasonCode(3)
|
||||||
|
Superseded = RevocationReasonCode(4)
|
||||||
|
CessationOfOperation = RevocationReasonCode(5)
|
||||||
|
CertificateHold = RevocationReasonCode(6)
|
||||||
|
RemoveFromCRL = RevocationReasonCode(8)
|
||||||
|
PrivilegeWithdrawn = RevocationReasonCode(9)
|
||||||
|
AACompromise = RevocationReasonCode(10)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReasonFlag holds a bitmask of applicable revocation reasons, from RFC 5280 s4.2.1.13
|
||||||
|
type ReasonFlag int
|
||||||
|
|
||||||
|
// ReasonFlag values.
|
||||||
|
const (
|
||||||
|
UnusedFlag ReasonFlag = 1 << iota
|
||||||
|
KeyCompromiseFlag
|
||||||
|
CACompromiseFlag
|
||||||
|
AffiliationChangedFlag
|
||||||
|
SupersededFlag
|
||||||
|
CessationOfOperationFlag
|
||||||
|
CertificateHoldFlag
|
||||||
|
PrivilegeWithdrawnFlag
|
||||||
|
AACompromiseFlag
|
||||||
|
)
|
||||||
|
|
||||||
|
// CertificateList represents the ASN.1 structure of the same name from RFC 5280, s5.1.
|
||||||
|
// It has the same content as pkix.CertificateList, but the contents include parsed versions
|
||||||
|
// of any extensions.
|
||||||
|
type CertificateList struct {
|
||||||
|
Raw asn1.RawContent
|
||||||
|
TBSCertList TBSCertList
|
||||||
|
SignatureAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
SignatureValue asn1.BitString
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpiredAt reports whether now is past the expiry time of certList.
|
||||||
|
func (certList *CertificateList) ExpiredAt(now time.Time) bool {
|
||||||
|
return now.After(certList.TBSCertList.NextUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indication of whether extensions need to be critical or non-critical. Extensions that
|
||||||
|
// can be either are omitted from the map.
|
||||||
|
var listExtCritical = map[string]bool{
|
||||||
|
// From RFC 5280...
|
||||||
|
OIDExtensionAuthorityKeyId.String(): false, // s5.2.1
|
||||||
|
OIDExtensionIssuerAltName.String(): false, // s5.2.2
|
||||||
|
OIDExtensionCRLNumber.String(): false, // s5.2.3
|
||||||
|
OIDExtensionDeltaCRLIndicator.String(): true, // s5.2.4
|
||||||
|
OIDExtensionIssuingDistributionPoint.String(): true, // s5.2.5
|
||||||
|
OIDExtensionFreshestCRL.String(): false, // s5.2.6
|
||||||
|
OIDExtensionAuthorityInfoAccess.String(): false, // s5.2.7
|
||||||
|
}
|
||||||
|
|
||||||
|
var certExtCritical = map[string]bool{
|
||||||
|
// From RFC 5280...
|
||||||
|
OIDExtensionCRLReasons.String(): false, // s5.3.1
|
||||||
|
OIDExtensionInvalidityDate.String(): false, // s5.3.2
|
||||||
|
OIDExtensionCertificateIssuer.String(): true, // s5.3.3
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssuingDistributionPoint represents the ASN.1 structure of the same
|
||||||
|
// name
|
||||||
|
type IssuingDistributionPoint struct {
|
||||||
|
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
|
||||||
|
OnlyContainsUserCerts bool `asn1:"optional,tag:1"`
|
||||||
|
OnlyContainsCACerts bool `asn1:"optional,tag:2"`
|
||||||
|
OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"`
|
||||||
|
IndirectCRL bool `asn1:"optional,tag:4"`
|
||||||
|
OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBSCertList represents the ASN.1 structure of the same name from RFC
|
||||||
|
// 5280, section 5.1. It has the same content as pkix.TBSCertificateList
|
||||||
|
// but the extensions are included in a parsed format.
|
||||||
|
type TBSCertList struct {
|
||||||
|
Raw asn1.RawContent
|
||||||
|
Version int
|
||||||
|
Signature pkix.AlgorithmIdentifier
|
||||||
|
Issuer pkix.RDNSequence
|
||||||
|
ThisUpdate time.Time
|
||||||
|
NextUpdate time.Time
|
||||||
|
RevokedCertificates []*RevokedCertificate
|
||||||
|
Extensions []pkix.Extension
|
||||||
|
// Cracked out extensions:
|
||||||
|
AuthorityKeyID []byte
|
||||||
|
IssuerAltNames GeneralNames
|
||||||
|
CRLNumber int
|
||||||
|
BaseCRLNumber int // -1 if no delta CRL present
|
||||||
|
IssuingDistributionPoint IssuingDistributionPoint
|
||||||
|
IssuingDPFullNames GeneralNames
|
||||||
|
FreshestCRLDistributionPoint []string
|
||||||
|
OCSPServer []string
|
||||||
|
IssuingCertificateURL []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCertificateList parses a CertificateList (e.g. a CRL) from the given
|
||||||
|
// bytes. It's often the case that PEM encoded CRLs will appear where they
|
||||||
|
// should be DER encoded, so this function will transparently handle PEM
|
||||||
|
// encoding as long as there isn't any leading garbage.
|
||||||
|
func ParseCertificateList(clBytes []byte) (*CertificateList, error) {
|
||||||
|
if bytes.HasPrefix(clBytes, pemCRLPrefix) {
|
||||||
|
block, _ := pem.Decode(clBytes)
|
||||||
|
if block != nil && block.Type == pemType {
|
||||||
|
clBytes = block.Bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ParseCertificateListDER(clBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCertificateListDER parses a DER encoded CertificateList from the given bytes.
|
||||||
|
// For non-fatal errors, this function returns both an error and a CertificateList
|
||||||
|
// object.
|
||||||
|
func ParseCertificateListDER(derBytes []byte) (*CertificateList, error) {
|
||||||
|
var errs Errors
|
||||||
|
// First parse the DER into the pkix structures.
|
||||||
|
pkixList := new(pkix.CertificateList)
|
||||||
|
if rest, err := asn1.Unmarshal(derBytes, pkixList); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertList, err)
|
||||||
|
return nil, &errs
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertList)
|
||||||
|
return nil, &errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transcribe the revoked certs but crack out extensions.
|
||||||
|
revokedCerts := make([]*RevokedCertificate, len(pkixList.TBSCertList.RevokedCertificates))
|
||||||
|
for i, pkixRevoked := range pkixList.TBSCertList.RevokedCertificates {
|
||||||
|
revokedCerts[i] = parseRevokedCertificate(pkixRevoked, &errs)
|
||||||
|
if revokedCerts[i] == nil {
|
||||||
|
return nil, &errs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
certList := CertificateList{
|
||||||
|
Raw: derBytes,
|
||||||
|
TBSCertList: TBSCertList{
|
||||||
|
Raw: pkixList.TBSCertList.Raw,
|
||||||
|
Version: pkixList.TBSCertList.Version,
|
||||||
|
Signature: pkixList.TBSCertList.Signature,
|
||||||
|
Issuer: pkixList.TBSCertList.Issuer,
|
||||||
|
ThisUpdate: pkixList.TBSCertList.ThisUpdate,
|
||||||
|
NextUpdate: pkixList.TBSCertList.NextUpdate,
|
||||||
|
RevokedCertificates: revokedCerts,
|
||||||
|
Extensions: pkixList.TBSCertList.Extensions,
|
||||||
|
CRLNumber: -1,
|
||||||
|
BaseCRLNumber: -1,
|
||||||
|
},
|
||||||
|
SignatureAlgorithm: pkixList.SignatureAlgorithm,
|
||||||
|
SignatureValue: pkixList.SignatureValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now crack out extensions.
|
||||||
|
for _, e := range certList.TBSCertList.Extensions {
|
||||||
|
if expectCritical, present := listExtCritical[e.Id.String()]; present {
|
||||||
|
if e.Critical && !expectCritical {
|
||||||
|
errs.AddID(ErrUnexpectedlyCriticalCertListExtension, e.Id)
|
||||||
|
} else if !e.Critical && expectCritical {
|
||||||
|
errs.AddID(ErrUnexpectedlyNonCriticalCertListExtension, e.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case e.Id.Equal(OIDExtensionAuthorityKeyId):
|
||||||
|
// RFC 5280 s5.2.1
|
||||||
|
var a authKeyId
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListAuthKeyID, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertListAuthKeyID)
|
||||||
|
}
|
||||||
|
certList.TBSCertList.AuthorityKeyID = a.Id
|
||||||
|
case e.Id.Equal(OIDExtensionIssuerAltName):
|
||||||
|
// RFC 5280 s5.2.2
|
||||||
|
if err := parseGeneralNames(e.Value, &certList.TBSCertList.IssuerAltNames); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListIssuerAltName, err)
|
||||||
|
}
|
||||||
|
case e.Id.Equal(OIDExtensionCRLNumber):
|
||||||
|
// RFC 5280 s5.2.3
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.CRLNumber); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListCRLNumber, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertListCRLNumber)
|
||||||
|
}
|
||||||
|
if certList.TBSCertList.CRLNumber < 0 {
|
||||||
|
errs.AddID(ErrNegativeCertListCRLNumber, certList.TBSCertList.CRLNumber)
|
||||||
|
}
|
||||||
|
case e.Id.Equal(OIDExtensionDeltaCRLIndicator):
|
||||||
|
// RFC 5280 s5.2.4
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.BaseCRLNumber); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListDeltaCRL, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertListDeltaCRL)
|
||||||
|
}
|
||||||
|
if certList.TBSCertList.BaseCRLNumber < 0 {
|
||||||
|
errs.AddID(ErrNegativeCertListDeltaCRL, certList.TBSCertList.BaseCRLNumber)
|
||||||
|
}
|
||||||
|
case e.Id.Equal(OIDExtensionIssuingDistributionPoint):
|
||||||
|
parseIssuingDistributionPoint(e.Value, &certList.TBSCertList.IssuingDistributionPoint, &certList.TBSCertList.IssuingDPFullNames, &errs)
|
||||||
|
case e.Id.Equal(OIDExtensionFreshestCRL):
|
||||||
|
// RFC 5280 s5.2.6
|
||||||
|
if err := parseDistributionPoints(e.Value, &certList.TBSCertList.FreshestCRLDistributionPoint); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListFreshestCRL, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case e.Id.Equal(OIDExtensionAuthorityInfoAccess):
|
||||||
|
// RFC 5280 s5.2.7
|
||||||
|
var aia []authorityInfoAccess
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListAuthInfoAccess, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertListAuthInfoAccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range aia {
|
||||||
|
// GeneralName: uniformResourceIdentifier [6] IA5String
|
||||||
|
if v.Location.Tag != tagURI {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case v.Method.Equal(OIDAuthorityInfoAccessOCSP):
|
||||||
|
certList.TBSCertList.OCSPServer = append(certList.TBSCertList.OCSPServer, string(v.Location.Bytes))
|
||||||
|
case v.Method.Equal(OIDAuthorityInfoAccessIssuers):
|
||||||
|
certList.TBSCertList.IssuingCertificateURL = append(certList.TBSCertList.IssuingCertificateURL, string(v.Location.Bytes))
|
||||||
|
}
|
||||||
|
// TODO(drysdale): cope with more possibilities
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if e.Critical {
|
||||||
|
errs.AddID(ErrUnhandledCriticalCertListExtension, e.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs.Fatal() {
|
||||||
|
return nil, &errs
|
||||||
|
}
|
||||||
|
if errs.Empty() {
|
||||||
|
return &certList, nil
|
||||||
|
}
|
||||||
|
return &certList, &errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseIssuingDistributionPoint(data []byte, idp *IssuingDistributionPoint, name *GeneralNames, errs *Errors) {
|
||||||
|
// RFC 5280 s5.2.5
|
||||||
|
if rest, err := asn1.Unmarshal(data, idp); err != nil {
|
||||||
|
errs.AddID(ErrInvalidCertListIssuingDP, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingCertListIssuingDP)
|
||||||
|
}
|
||||||
|
|
||||||
|
typeCount := 0
|
||||||
|
if idp.OnlyContainsUserCerts {
|
||||||
|
typeCount++
|
||||||
|
}
|
||||||
|
if idp.OnlyContainsCACerts {
|
||||||
|
typeCount++
|
||||||
|
}
|
||||||
|
if idp.OnlyContainsAttributeCerts {
|
||||||
|
typeCount++
|
||||||
|
}
|
||||||
|
if typeCount > 1 {
|
||||||
|
errs.AddID(ErrCertListIssuingDPMultipleTypes, idp.OnlyContainsUserCerts, idp.OnlyContainsCACerts, idp.OnlyContainsAttributeCerts)
|
||||||
|
}
|
||||||
|
for _, fn := range idp.DistributionPoint.FullName {
|
||||||
|
if _, err := parseGeneralName(fn.FullBytes, name, false); err != nil {
|
||||||
|
errs.AddID(ErrCertListIssuingDPInvalidFullName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokedCertificate represents the unnamed ASN.1 structure that makes up the
|
||||||
|
// revokedCertificates member of the TBSCertList structure from RFC 5280, s5.1.
|
||||||
|
// It has the same content as pkix.RevokedCertificate but the extensions are
|
||||||
|
// included in a parsed format.
|
||||||
|
type RevokedCertificate struct {
|
||||||
|
pkix.RevokedCertificate
|
||||||
|
// Cracked out extensions:
|
||||||
|
RevocationReason RevocationReasonCode
|
||||||
|
InvalidityDate time.Time
|
||||||
|
Issuer GeneralNames
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRevokedCertificate(pkixRevoked pkix.RevokedCertificate, errs *Errors) *RevokedCertificate {
|
||||||
|
result := RevokedCertificate{RevokedCertificate: pkixRevoked}
|
||||||
|
for _, e := range pkixRevoked.Extensions {
|
||||||
|
if expectCritical, present := certExtCritical[e.Id.String()]; present {
|
||||||
|
if e.Critical && !expectCritical {
|
||||||
|
errs.AddID(ErrUnexpectedlyCriticalRevokedCertExtension, e.Id)
|
||||||
|
} else if !e.Critical && expectCritical {
|
||||||
|
errs.AddID(ErrUnexpectedlyNonCriticalRevokedCertExtension, e.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case e.Id.Equal(OIDExtensionCRLReasons):
|
||||||
|
// RFC 5280, s5.3.1
|
||||||
|
var reason asn1.Enumerated
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &reason); err != nil {
|
||||||
|
errs.AddID(ErrInvalidRevocationReason, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingRevocationReason)
|
||||||
|
}
|
||||||
|
result.RevocationReason = RevocationReasonCode(reason)
|
||||||
|
case e.Id.Equal(OIDExtensionInvalidityDate):
|
||||||
|
// RFC 5280, s5.3.2
|
||||||
|
if rest, err := asn1.Unmarshal(e.Value, &result.InvalidityDate); err != nil {
|
||||||
|
errs.AddID(ErrInvalidRevocationInvalidityDate, err)
|
||||||
|
} else if len(rest) != 0 {
|
||||||
|
errs.AddID(ErrTrailingRevocationInvalidityDate)
|
||||||
|
}
|
||||||
|
case e.Id.Equal(OIDExtensionCertificateIssuer):
|
||||||
|
// RFC 5280, s5.3.3
|
||||||
|
if err := parseGeneralNames(e.Value, &result.Issuer); err != nil {
|
||||||
|
errs.AddID(ErrInvalidRevocationIssuer, err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if e.Critical {
|
||||||
|
errs.AddID(ErrUnhandledCriticalRevokedCertExtension, e.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCertificateListSignature checks that the signature in crl is from c.
|
||||||
|
func (c *Certificate) CheckCertificateListSignature(crl *CertificateList) error {
|
||||||
|
algo := SignatureAlgorithmFromAI(crl.SignatureAlgorithm)
|
||||||
|
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
|
||||||
|
}
|
||||||
5
vendor/github.com/google/certificate-transparency/go/x509/root.go → vendor/github.com/google/certificate-transparency-go/x509/root.go
generated
vendored
Executable file → Normal file
5
vendor/github.com/google/certificate-transparency/go/x509/root.go → vendor/github.com/google/certificate-transparency-go/x509/root.go
generated
vendored
Executable file → Normal file
@@ -9,9 +9,14 @@ import "sync"
|
|||||||
var (
|
var (
|
||||||
once sync.Once
|
once sync.Once
|
||||||
systemRoots *CertPool
|
systemRoots *CertPool
|
||||||
|
systemRootsErr error
|
||||||
)
|
)
|
||||||
|
|
||||||
func systemRootsPool() *CertPool {
|
func systemRootsPool() *CertPool {
|
||||||
once.Do(initSystemRoots)
|
once.Do(initSystemRoots)
|
||||||
return systemRoots
|
return systemRoots
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initSystemRoots() {
|
||||||
|
systemRoots, systemRootsErr = loadSystemRoots()
|
||||||
|
}
|
||||||
15
vendor/github.com/google/certificate-transparency-go/x509/root_bsd.go
generated
vendored
Normal file
15
vendor/github.com/google/certificate-transparency-go/x509/root_bsd.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
// Possible certificate files; stop after finding one.
|
||||||
|
var certFiles = []string{
|
||||||
|
"/usr/local/etc/ssl/cert.pem", // FreeBSD
|
||||||
|
"/etc/ssl/cert.pem", // OpenBSD
|
||||||
|
"/usr/local/share/certs/ca-root-nss.crt", // DragonFly
|
||||||
|
"/etc/openssl/certs/ca-certificates.crt", // NetBSD
|
||||||
|
}
|
||||||
252
vendor/github.com/google/certificate-transparency-go/x509/root_cgo_darwin.go
generated
vendored
Normal file
252
vendor/github.com/google/certificate-transparency-go/x509/root_cgo_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo,!arm,!arm64,!ios
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
|
||||||
|
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <Security/Security.h>
|
||||||
|
|
||||||
|
// FetchPEMRootsCTX509_MountainLion is the version of FetchPEMRoots from Go 1.6
|
||||||
|
// which still works on OS X 10.8 (Mountain Lion).
|
||||||
|
// It lacks support for admin & user cert domains.
|
||||||
|
// See golang.org/issue/16473
|
||||||
|
int FetchPEMRootsCTX509_MountainLion(CFDataRef *pemRoots) {
|
||||||
|
if (pemRoots == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CFArrayRef certs = NULL;
|
||||||
|
OSStatus err = SecTrustCopyAnchorCertificates(&certs);
|
||||||
|
if (err != noErr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||||
|
int i, ncerts = CFArrayGetCount(certs);
|
||||||
|
for (i = 0; i < ncerts; i++) {
|
||||||
|
CFDataRef data = NULL;
|
||||||
|
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
|
||||||
|
if (cert == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
|
||||||
|
// Once we support weak imports via cgo we should prefer that, and fall back to this
|
||||||
|
// for older systems.
|
||||||
|
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
||||||
|
if (err != noErr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (data != NULL) {
|
||||||
|
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||||
|
CFRelease(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(certs);
|
||||||
|
*pemRoots = combinedData;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// useOldCodeCTX509 reports whether the running machine is OS X 10.8 Mountain Lion
|
||||||
|
// or older. We only support Mountain Lion and higher, but we'll at least try our
|
||||||
|
// best on older machines and continue to use the old code path.
|
||||||
|
//
|
||||||
|
// See golang.org/issue/16473
|
||||||
|
int useOldCodeCTX509() {
|
||||||
|
char str[256];
|
||||||
|
size_t size = sizeof(str);
|
||||||
|
memset(str, 0, size);
|
||||||
|
sysctlbyname("kern.osrelease", str, &size, NULL, 0);
|
||||||
|
// OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*.
|
||||||
|
// We never supported things before that.
|
||||||
|
return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchPEMRootsCTX509 fetches the system's list of trusted X.509 root certificates.
|
||||||
|
//
|
||||||
|
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
|
||||||
|
// certificates of the system. On failure, the function returns -1.
|
||||||
|
// Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
|
||||||
|
//
|
||||||
|
// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
|
||||||
|
// be released (using CFRelease) after we've consumed its content.
|
||||||
|
int FetchPEMRootsCTX509(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
|
||||||
|
if (useOldCodeCTX509()) {
|
||||||
|
return FetchPEMRootsCTX509_MountainLion(pemRoots);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get certificates from all domains, not just System, this lets
|
||||||
|
// the user add CAs to their "login" keychain, and Admins to add
|
||||||
|
// to the "System" keychain
|
||||||
|
SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
|
||||||
|
kSecTrustSettingsDomainAdmin,
|
||||||
|
kSecTrustSettingsDomainUser };
|
||||||
|
|
||||||
|
int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
|
||||||
|
if (pemRoots == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
|
||||||
|
// but the Go linker's internal linking mode can't handle CFSTR relocations.
|
||||||
|
// Create our own dynamic string instead and release it below.
|
||||||
|
CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||||
|
CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||||
|
for (int i = 0; i < numDomains; i++) {
|
||||||
|
CFArrayRef certs = NULL;
|
||||||
|
OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
|
||||||
|
if (err != noErr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFIndex numCerts = CFArrayGetCount(certs);
|
||||||
|
for (int j = 0; j < numCerts; j++) {
|
||||||
|
CFDataRef data = NULL;
|
||||||
|
CFErrorRef errRef = NULL;
|
||||||
|
CFArrayRef trustSettings = NULL;
|
||||||
|
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
|
||||||
|
if (cert == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We only want trusted certs.
|
||||||
|
int untrusted = 0;
|
||||||
|
int trustAsRoot = 0;
|
||||||
|
int trustRoot = 0;
|
||||||
|
if (i == 0) {
|
||||||
|
trustAsRoot = 1;
|
||||||
|
} else {
|
||||||
|
// Certs found in the system domain are always trusted. If the user
|
||||||
|
// configures "Never Trust" on such a cert, it will also be found in the
|
||||||
|
// admin or user domain, causing it to be added to untrustedPemRoots. The
|
||||||
|
// Go code will then clean this up.
|
||||||
|
|
||||||
|
// Trust may be stored in any of the domains. According to Apple's
|
||||||
|
// SecTrustServer.c, "user trust settings overrule admin trust settings",
|
||||||
|
// so take the last trust settings array we find.
|
||||||
|
// Skip the system domain since it is always trusted.
|
||||||
|
for (int k = i; k < numDomains; k++) {
|
||||||
|
CFArrayRef domainTrustSettings = NULL;
|
||||||
|
err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
|
||||||
|
if (err == errSecSuccess && domainTrustSettings != NULL) {
|
||||||
|
if (trustSettings) {
|
||||||
|
CFRelease(trustSettings);
|
||||||
|
}
|
||||||
|
trustSettings = domainTrustSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (trustSettings == NULL) {
|
||||||
|
// "this certificate must be verified to a known trusted certificate"; aka not a root.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (CFIndex k = 0; k < CFArrayGetCount(trustSettings); k++) {
|
||||||
|
CFNumberRef cfNum;
|
||||||
|
CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, k);
|
||||||
|
if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
|
||||||
|
SInt32 result = 0;
|
||||||
|
CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
|
||||||
|
// TODO: The rest of the dictionary specifies conditions for evaluation.
|
||||||
|
if (result == kSecTrustSettingsResultDeny) {
|
||||||
|
untrusted = 1;
|
||||||
|
} else if (result == kSecTrustSettingsResultTrustAsRoot) {
|
||||||
|
trustAsRoot = 1;
|
||||||
|
} else if (result == kSecTrustSettingsResultTrustRoot) {
|
||||||
|
trustRoot = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(trustSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trustRoot) {
|
||||||
|
// We only want to add Root CAs, so make sure Subject and Issuer Name match
|
||||||
|
CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
|
||||||
|
if (errRef != NULL) {
|
||||||
|
CFRelease(errRef);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
|
||||||
|
if (errRef != NULL) {
|
||||||
|
CFRelease(subjectName);
|
||||||
|
CFRelease(errRef);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Boolean equal = CFEqual(subjectName, issuerName);
|
||||||
|
CFRelease(subjectName);
|
||||||
|
CFRelease(issuerName);
|
||||||
|
if (!equal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
|
||||||
|
// Once we support weak imports via cgo we should prefer that, and fall back to this
|
||||||
|
// for older systems.
|
||||||
|
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
||||||
|
if (err != noErr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
if (!trustRoot && !trustAsRoot) {
|
||||||
|
untrusted = 1;
|
||||||
|
}
|
||||||
|
CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
|
||||||
|
CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||||
|
CFRelease(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(certs);
|
||||||
|
}
|
||||||
|
CFRelease(policy);
|
||||||
|
*pemRoots = combinedData;
|
||||||
|
*untrustedPemRoots = combinedUntrustedData;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
|
roots := NewCertPool()
|
||||||
|
|
||||||
|
var data C.CFDataRef
|
||||||
|
setNilCFRef(&data)
|
||||||
|
var untrustedData C.CFDataRef
|
||||||
|
setNilCFRef(&untrustedData)
|
||||||
|
err := C.FetchPEMRootsCTX509(&data, &untrustedData)
|
||||||
|
if err == -1 {
|
||||||
|
// TODO: better error message
|
||||||
|
return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer C.CFRelease(C.CFTypeRef(data))
|
||||||
|
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
|
||||||
|
roots.AppendCertsFromPEM(buf)
|
||||||
|
if isNilCFRef(untrustedData) {
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
defer C.CFRelease(C.CFTypeRef(untrustedData))
|
||||||
|
buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
|
||||||
|
untrustedRoots := NewCertPool()
|
||||||
|
untrustedRoots.AppendCertsFromPEM(buf)
|
||||||
|
|
||||||
|
trustedRoots := NewCertPool()
|
||||||
|
for _, c := range roots.certs {
|
||||||
|
if !untrustedRoots.contains(c) {
|
||||||
|
trustedRoots.AddCert(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trustedRoots, nil
|
||||||
|
}
|
||||||
264
vendor/github.com/google/certificate-transparency-go/x509/root_darwin.go
generated
vendored
Normal file
264
vendor/github.com/google/certificate-transparency-go/x509/root_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
|
||||||
|
|
||||||
|
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This code is only used when compiling without cgo.
|
||||||
|
// It is here, instead of root_nocgo_darwin.go, so that tests can check it
|
||||||
|
// even if the tests are run with cgo enabled.
|
||||||
|
// The linker will not include these unused functions in binaries built with cgo enabled.
|
||||||
|
|
||||||
|
// execSecurityRoots finds the macOS list of trusted root certificates
|
||||||
|
// using only command-line tools. This is our fallback path when cgo isn't available.
|
||||||
|
//
|
||||||
|
// The strategy is as follows:
|
||||||
|
//
|
||||||
|
// 1. Run "security trust-settings-export" and "security
|
||||||
|
// trust-settings-export -d" to discover the set of certs with some
|
||||||
|
// user-tweaked trust policy. We're too lazy to parse the XML (at
|
||||||
|
// least at this stage of Go 1.8) to understand what the trust
|
||||||
|
// policy actually is. We just learn that there is _some_ policy.
|
||||||
|
//
|
||||||
|
// 2. Run "security find-certificate" to dump the list of system root
|
||||||
|
// CAs in PEM format.
|
||||||
|
//
|
||||||
|
// 3. For each dumped cert, conditionally verify it with "security
|
||||||
|
// verify-cert" if that cert was in the set discovered in Step 1.
|
||||||
|
// Without the Step 1 optimization, running "security verify-cert"
|
||||||
|
// 150-200 times takes 3.5 seconds. With the optimization, the
|
||||||
|
// whole process takes about 180 milliseconds with 1 untrusted root
|
||||||
|
// CA. (Compared to 110ms in the cgo path)
|
||||||
|
func execSecurityRoots() (*CertPool, error) {
|
||||||
|
hasPolicy, err := getCertsWithTrustPolicy()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"find-certificate", "-a", "-p",
|
||||||
|
"/System/Library/Keychains/SystemRootCertificates.keychain",
|
||||||
|
"/Library/Keychains/System.keychain",
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
println(fmt.Sprintf("crypto/x509: get current user: %v", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = append(args,
|
||||||
|
filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"),
|
||||||
|
|
||||||
|
// Fresh installs of Sierra use a slightly different path for the login keychain
|
||||||
|
filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain-db"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("/usr/bin/security", args...)
|
||||||
|
data, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
roots = NewCertPool()
|
||||||
|
numVerified int // number of execs of 'security verify-cert', for debug stats
|
||||||
|
)
|
||||||
|
|
||||||
|
blockCh := make(chan *pem.Block)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Using 4 goroutines to pipe into verify-cert seems to be
|
||||||
|
// about the best we can do. The verify-cert binary seems to
|
||||||
|
// just RPC to another server with coarse locking anyway, so
|
||||||
|
// running 16 at a time for instance doesn't help at all. Due
|
||||||
|
// to the "if hasPolicy" check below, though, we will rarely
|
||||||
|
// (or never) call verify-cert on stock macOS systems, though.
|
||||||
|
// The hope is that we only call verify-cert when the user has
|
||||||
|
// tweaked their trust policy. These 4 goroutines are only
|
||||||
|
// defensive in the pathological case of many trust edits.
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for block := range blockCh {
|
||||||
|
cert, err := ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
|
||||||
|
|
||||||
|
valid := true
|
||||||
|
verifyChecks := 0
|
||||||
|
if hasPolicy[sha1CapHex] {
|
||||||
|
verifyChecks++
|
||||||
|
if !verifyCertWithSystem(block, cert) {
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
numVerified += verifyChecks
|
||||||
|
if valid {
|
||||||
|
roots.AddCert(cert)
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
for len(data) > 0 {
|
||||||
|
var block *pem.Block
|
||||||
|
block, data = pem.Decode(data)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
blockCh <- block
|
||||||
|
}
|
||||||
|
close(blockCh)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
|
||||||
|
}
|
||||||
|
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
|
||||||
|
data := pem.EncodeToMemory(block)
|
||||||
|
|
||||||
|
f, err := ioutil.TempFile("", "cert")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
if _, err := f.Write(data); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCertsWithTrustPolicy returns the set of certs that have a
|
||||||
|
// possibly-altered trust policy. The keys of the map are capitalized
|
||||||
|
// sha1 hex of the raw cert.
|
||||||
|
// They are the certs that should be checked against `security
|
||||||
|
// verify-cert` to see whether the user altered the default trust
|
||||||
|
// settings. This code is only used for cgo-disabled builds.
|
||||||
|
func getCertsWithTrustPolicy() (map[string]bool, error) {
|
||||||
|
set := map[string]bool{}
|
||||||
|
td, err := ioutil.TempDir("", "x509trustpolicy")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(td)
|
||||||
|
run := func(file string, args ...string) error {
|
||||||
|
file = filepath.Join(td, file)
|
||||||
|
args = append(args, file)
|
||||||
|
cmd := exec.Command("/usr/bin/security", args...)
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
// If there are no trust settings, the
|
||||||
|
// `security trust-settings-export` command
|
||||||
|
// fails with:
|
||||||
|
// exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
|
||||||
|
// Rather than match on English substrings that are probably
|
||||||
|
// localized on macOS, just interpret any failure to mean that
|
||||||
|
// there are no trust settings.
|
||||||
|
if debugExecDarwinRoots {
|
||||||
|
println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Gather all the runs of 40 capitalized hex characters.
|
||||||
|
br := bufio.NewReader(f)
|
||||||
|
var hexBuf bytes.Buffer
|
||||||
|
for {
|
||||||
|
b, err := br.ReadByte()
|
||||||
|
isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
|
||||||
|
if isHex {
|
||||||
|
hexBuf.WriteByte(b)
|
||||||
|
} else {
|
||||||
|
if hexBuf.Len() == 40 {
|
||||||
|
set[hexBuf.String()] = true
|
||||||
|
}
|
||||||
|
hexBuf.Reset()
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := run("user", "trust-settings-export"); err != nil {
|
||||||
|
return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
|
||||||
|
}
|
||||||
|
if err := run("admin", "trust-settings-export", "-d"); err != nil {
|
||||||
|
return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
|
||||||
|
}
|
||||||
|
return set, nil
|
||||||
|
}
|
||||||
187
vendor/github.com/google/certificate-transparency-go/x509/root_darwin_arm_gen.go
generated
vendored
Normal file
187
vendor/github.com/google/certificate-transparency-go/x509/root_darwin_arm_gen.go
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
// Generates root_darwin_armx.go.
|
||||||
|
//
|
||||||
|
// As of iOS 8, there is no API for querying the system trusted X.509 root
|
||||||
|
// certificates. We could use SecTrustEvaluate to verify that a trust chain
|
||||||
|
// exists for a certificate, but the x509 API requires returning the entire
|
||||||
|
// chain.
|
||||||
|
//
|
||||||
|
// Apple publishes the list of trusted root certificates for iOS on
|
||||||
|
// support.apple.com. So we parse the list and extract the certificates from
|
||||||
|
// an OS X machine and embed them into the x509 package.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/pem"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
var output = flag.String("output", "root_darwin_armx.go", "file name to write")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
certs, err := selectCerts()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
|
||||||
|
fmt.Fprintf(buf, "%s", header)
|
||||||
|
|
||||||
|
fmt.Fprintf(buf, "const systemRootsPEM = `\n")
|
||||||
|
for _, cert := range certs {
|
||||||
|
b := &pem.Block{
|
||||||
|
Type: "CERTIFICATE",
|
||||||
|
Bytes: cert.Raw,
|
||||||
|
}
|
||||||
|
if err := pem.Encode(buf, b); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "`")
|
||||||
|
|
||||||
|
source, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("source format error:", err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(*output, source, 0644); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectCerts() ([]*x509.Certificate, error) {
|
||||||
|
ids, err := fetchCertIDs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
scerts, err := sysCerts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var certs []*x509.Certificate
|
||||||
|
for _, id := range ids {
|
||||||
|
if c, ok := scerts[id.fingerprint]; ok {
|
||||||
|
certs = append(certs, c)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return certs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sysCerts() (certs map[string]*x509.Certificate, err error) {
|
||||||
|
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
|
||||||
|
data, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
certs = make(map[string]*x509.Certificate)
|
||||||
|
for len(data) > 0 {
|
||||||
|
var block *pem.Block
|
||||||
|
block, data = pem.Decode(data)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fingerprint := sha256.Sum256(cert.Raw)
|
||||||
|
certs[hex.EncodeToString(fingerprint[:])] = cert
|
||||||
|
}
|
||||||
|
return certs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type certID struct {
|
||||||
|
name string
|
||||||
|
fingerprint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
|
||||||
|
func fetchCertIDs() ([]certID, error) {
|
||||||
|
// Download the iOS 11 support page. The index for all iOS versions is here:
|
||||||
|
// https://support.apple.com/en-us/HT204132
|
||||||
|
resp, err := http.Get("https://support.apple.com/en-us/HT208125")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
text := string(body)
|
||||||
|
text = text[strings.Index(text, "<div id=trusted"):]
|
||||||
|
text = text[:strings.Index(text, "</div>")]
|
||||||
|
|
||||||
|
var ids []certID
|
||||||
|
cols := make(map[string]int)
|
||||||
|
for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
|
||||||
|
row := rowmatch[1]
|
||||||
|
if i == 0 {
|
||||||
|
// Parse table header row to extract column names
|
||||||
|
for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
|
||||||
|
cols[match[1]] = i
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
|
||||||
|
name := values[cols["Certificate name"]][1]
|
||||||
|
fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
|
||||||
|
fingerprint = strings.Replace(fingerprint, "<br>", "", -1)
|
||||||
|
fingerprint = strings.Replace(fingerprint, "\n", "", -1)
|
||||||
|
fingerprint = strings.Replace(fingerprint, " ", "", -1)
|
||||||
|
fingerprint = strings.ToLower(fingerprint)
|
||||||
|
|
||||||
|
ids = append(ids, certID{
|
||||||
|
name: name,
|
||||||
|
fingerprint: fingerprint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = `
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
// +build darwin
|
||||||
|
// +build arm arm64 ios
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
|
p := NewCertPool()
|
||||||
|
p.AppendCertsFromPEM([]byte(systemRootsPEM))
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
`
|
||||||
4313
vendor/github.com/google/certificate-transparency-go/x509/root_darwin_armx.go
generated
vendored
Normal file
4313
vendor/github.com/google/certificate-transparency-go/x509/root_darwin_armx.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14
vendor/github.com/google/certificate-transparency-go/x509/root_linux.go
generated
vendored
Normal file
14
vendor/github.com/google/certificate-transparency-go/x509/root_linux.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
// Possible certificate files; stop after finding one.
|
||||||
|
var certFiles = []string{
|
||||||
|
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||||
|
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||||
|
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||||
|
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||||
|
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
|
||||||
|
}
|
||||||
8
vendor/github.com/google/certificate-transparency-go/x509/root_nacl.go
generated
vendored
Normal file
8
vendor/github.com/google/certificate-transparency-go/x509/root_nacl.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
// Possible certificate files; stop after finding one.
|
||||||
|
var certFiles = []string{}
|
||||||
11
vendor/github.com/google/certificate-transparency-go/x509/root_nocgo_darwin.go
generated
vendored
Normal file
11
vendor/github.com/google/certificate-transparency-go/x509/root_nocgo_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
|
return execSecurityRoots()
|
||||||
|
}
|
||||||
18
vendor/github.com/google/certificate-transparency/go/x509/root_plan9.go → vendor/github.com/google/certificate-transparency-go/x509/root_plan9.go
generated
vendored
Executable file → Normal file
18
vendor/github.com/google/certificate-transparency/go/x509/root_plan9.go → vendor/github.com/google/certificate-transparency-go/x509/root_plan9.go
generated
vendored
Executable file → Normal file
@@ -6,7 +6,10 @@
|
|||||||
|
|
||||||
package x509
|
package x509
|
||||||
|
|
||||||
import "io/ioutil"
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
// Possible certificate files; stop after finding one.
|
// Possible certificate files; stop after finding one.
|
||||||
var certFiles = []string{
|
var certFiles = []string{
|
||||||
@@ -17,17 +20,18 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSystemRoots() {
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
roots := NewCertPool()
|
roots := NewCertPool()
|
||||||
|
var bestErr error
|
||||||
for _, file := range certFiles {
|
for _, file := range certFiles {
|
||||||
data, err := ioutil.ReadFile(file)
|
data, err := ioutil.ReadFile(file)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
roots.AppendCertsFromPEM(data)
|
roots.AppendCertsFromPEM(data)
|
||||||
systemRoots = roots
|
return roots, nil
|
||||||
return
|
}
|
||||||
|
if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) {
|
||||||
|
bestErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil, bestErr
|
||||||
// All of the files failed to load. systemRoots will be nil which will
|
|
||||||
// trigger a specific error at verification time.
|
|
||||||
}
|
}
|
||||||
12
vendor/github.com/google/certificate-transparency-go/x509/root_solaris.go
generated
vendored
Normal file
12
vendor/github.com/google/certificate-transparency-go/x509/root_solaris.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
// Possible certificate files; stop after finding one.
|
||||||
|
var certFiles = []string{
|
||||||
|
"/etc/certs/ca-certificates.crt", // Solaris 11.2+
|
||||||
|
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
|
||||||
|
"/etc/ssl/cacert.pem", // OmniOS
|
||||||
|
}
|
||||||
88
vendor/github.com/google/certificate-transparency-go/x509/root_unix.go
generated
vendored
Normal file
88
vendor/github.com/google/certificate-transparency-go/x509/root_unix.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Possible directories with certificate files; stop after successfully
|
||||||
|
// reading at least one file from a directory.
|
||||||
|
var certDirectories = []string{
|
||||||
|
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
|
||||||
|
"/system/etc/security/cacerts", // Android
|
||||||
|
"/usr/local/share/certs", // FreeBSD
|
||||||
|
"/etc/pki/tls/certs", // Fedora/RHEL
|
||||||
|
"/etc/openssl/certs", // NetBSD
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// certFileEnv is the environment variable which identifies where to locate
|
||||||
|
// the SSL certificate file. If set this overrides the system default.
|
||||||
|
certFileEnv = "SSL_CERT_FILE"
|
||||||
|
|
||||||
|
// certDirEnv is the environment variable which identifies which directory
|
||||||
|
// to check for SSL certificate files. If set this overrides the system default.
|
||||||
|
certDirEnv = "SSL_CERT_DIR"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
|
roots := NewCertPool()
|
||||||
|
|
||||||
|
files := certFiles
|
||||||
|
if f := os.Getenv(certFileEnv); f != "" {
|
||||||
|
files = []string{f}
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstErr error
|
||||||
|
for _, file := range files {
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err == nil {
|
||||||
|
roots.AppendCertsFromPEM(data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if firstErr == nil && !os.IsNotExist(err) {
|
||||||
|
firstErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs := certDirectories
|
||||||
|
if d := os.Getenv(certDirEnv); d != "" {
|
||||||
|
dirs = []string{d}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, directory := range dirs {
|
||||||
|
fis, err := ioutil.ReadDir(directory)
|
||||||
|
if err != nil {
|
||||||
|
if firstErr == nil && !os.IsNotExist(err) {
|
||||||
|
firstErr = err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rootsAdded := false
|
||||||
|
for _, fi := range fis {
|
||||||
|
data, err := ioutil.ReadFile(directory + "/" + fi.Name())
|
||||||
|
if err == nil && roots.AppendCertsFromPEM(data) {
|
||||||
|
rootsAdded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rootsAdded {
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(roots.certs) > 0 {
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, firstErr
|
||||||
|
}
|
||||||
43
vendor/github.com/google/certificate-transparency/go/x509/root_windows.go → vendor/github.com/google/certificate-transparency-go/x509/root_windows.go
generated
vendored
Executable file → Normal file
43
vendor/github.com/google/certificate-transparency/go/x509/root_windows.go → vendor/github.com/google/certificate-transparency-go/x509/root_windows.go
generated
vendored
Executable file → Normal file
@@ -87,7 +87,7 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
|
|||||||
status := chainCtx.TrustStatus.ErrorStatus
|
status := chainCtx.TrustStatus.ErrorStatus
|
||||||
switch status {
|
switch status {
|
||||||
case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
|
case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
|
||||||
return CertificateInvalidError{c, Expired}
|
return CertificateInvalidError{c, Expired, ""}
|
||||||
default:
|
default:
|
||||||
return UnknownAuthorityError{c, nil, nil}
|
return UnknownAuthorityError{c, nil, nil}
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
|
|||||||
if status.Error != 0 {
|
if status.Error != 0 {
|
||||||
switch status.Error {
|
switch status.Error {
|
||||||
case syscall.CERT_E_EXPIRED:
|
case syscall.CERT_E_EXPIRED:
|
||||||
return CertificateInvalidError{c, Expired}
|
return CertificateInvalidError{c, Expired, ""}
|
||||||
case syscall.CERT_E_CN_NO_MATCH:
|
case syscall.CERT_E_CN_NO_MATCH:
|
||||||
return HostnameError{c, opts.DNSName}
|
return HostnameError{c, opts.DNSName}
|
||||||
case syscall.CERT_E_UNTRUSTEDROOT:
|
case syscall.CERT_E_UNTRUSTEDROOT:
|
||||||
@@ -225,5 +225,42 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
|||||||
return chains, nil
|
return chains, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSystemRoots() {
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
|
// TODO: restore this functionality on Windows. We tried to do
|
||||||
|
// it in Go 1.8 but had to revert it. See Issue 18609.
|
||||||
|
// Returning (nil, nil) was the old behavior, prior to CL 30578.
|
||||||
|
return nil, nil
|
||||||
|
|
||||||
|
const CRYPT_E_NOT_FOUND = 0x80092004
|
||||||
|
|
||||||
|
store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer syscall.CertCloseStore(store, 0)
|
||||||
|
|
||||||
|
roots := NewCertPool()
|
||||||
|
var cert *syscall.CertContext
|
||||||
|
for {
|
||||||
|
cert, err = syscall.CertEnumCertificatesInStore(store, cert)
|
||||||
|
if err != nil {
|
||||||
|
if errno, ok := err.(syscall.Errno); ok {
|
||||||
|
if errno == CRYPT_E_NOT_FOUND {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cert == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Copy the buf, since ParseCertificate does not create its own copy.
|
||||||
|
buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
|
||||||
|
buf2 := make([]byte, cert.Length)
|
||||||
|
copy(buf2, buf)
|
||||||
|
if c, err := ParseCertificate(buf2); err == nil {
|
||||||
|
roots.AddCert(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roots, nil
|
||||||
}
|
}
|
||||||
45
vendor/github.com/google/certificate-transparency/go/x509/sec1.go → vendor/github.com/google/certificate-transparency-go/x509/sec1.go
generated
vendored
Executable file → Normal file
45
vendor/github.com/google/certificate-transparency/go/x509/sec1.go → vendor/github.com/google/certificate-transparency-go/x509/sec1.go
generated
vendored
Executable file → Normal file
@@ -7,12 +7,11 @@ package x509
|
|||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
// START CT CHANGES
|
|
||||||
"github.com/google/certificate-transparency/go/asn1"
|
|
||||||
// START CT CHANGES
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/google/certificate-transparency-go/asn1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ecPrivKeyVersion = 1
|
const ecPrivKeyVersion = 1
|
||||||
@@ -20,7 +19,7 @@ const ecPrivKeyVersion = 1
|
|||||||
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
|
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
|
||||||
// References:
|
// References:
|
||||||
// RFC 5915
|
// RFC 5915
|
||||||
// SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf
|
// SEC1 - http://www.secg.org/sec1-v2.pdf
|
||||||
// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
|
// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
|
||||||
// most cases it is not.
|
// most cases it is not.
|
||||||
type ecPrivateKey struct {
|
type ecPrivateKey struct {
|
||||||
@@ -31,19 +30,30 @@ type ecPrivateKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
|
// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
|
||||||
func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error) {
|
func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) {
|
||||||
return parseECPrivateKey(nil, der)
|
return parseECPrivateKey(nil, der)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalECPrivateKey marshals an EC private key into ASN.1, DER format.
|
// MarshalECPrivateKey marshals an EC private key into ASN.1, DER format.
|
||||||
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
|
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
|
||||||
oid, ok := oidFromNamedCurve(key.Curve)
|
oid, ok := OIDFromNamedCurve(key.Curve)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("x509: unknown elliptic curve")
|
return nil, errors.New("x509: unknown elliptic curve")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return marshalECPrivateKeyWithOID(key, oid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalECPrivateKey marshals an EC private key into ASN.1, DER format and
|
||||||
|
// sets the curve ID to the given OID, or omits it if OID is nil.
|
||||||
|
func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) {
|
||||||
|
privateKeyBytes := key.D.Bytes()
|
||||||
|
paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
|
||||||
|
copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
|
||||||
|
|
||||||
return asn1.Marshal(ecPrivateKey{
|
return asn1.Marshal(ecPrivateKey{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
PrivateKey: key.D.Bytes(),
|
PrivateKey: paddedPrivateKey,
|
||||||
NamedCurveOID: oid,
|
NamedCurveOID: oid,
|
||||||
PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
|
PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
|
||||||
})
|
})
|
||||||
@@ -73,13 +83,30 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e
|
|||||||
}
|
}
|
||||||
|
|
||||||
k := new(big.Int).SetBytes(privKey.PrivateKey)
|
k := new(big.Int).SetBytes(privKey.PrivateKey)
|
||||||
if k.Cmp(curve.Params().N) >= 0 {
|
curveOrder := curve.Params().N
|
||||||
|
if k.Cmp(curveOrder) >= 0 {
|
||||||
return nil, errors.New("x509: invalid elliptic curve private key value")
|
return nil, errors.New("x509: invalid elliptic curve private key value")
|
||||||
}
|
}
|
||||||
priv := new(ecdsa.PrivateKey)
|
priv := new(ecdsa.PrivateKey)
|
||||||
priv.Curve = curve
|
priv.Curve = curve
|
||||||
priv.D = k
|
priv.D = k
|
||||||
priv.X, priv.Y = curve.ScalarBaseMult(privKey.PrivateKey)
|
|
||||||
|
privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
|
||||||
|
|
||||||
|
// Some private keys have leading zero padding. This is invalid
|
||||||
|
// according to [SEC1], but this code will ignore it.
|
||||||
|
for len(privKey.PrivateKey) > len(privateKey) {
|
||||||
|
if privKey.PrivateKey[0] != 0 {
|
||||||
|
return nil, errors.New("x509: invalid private key length")
|
||||||
|
}
|
||||||
|
privKey.PrivateKey = privKey.PrivateKey[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some private keys remove all leading zeros, this is also invalid
|
||||||
|
// according to [SEC1] but since OpenSSL used to do this, we ignore
|
||||||
|
// this too.
|
||||||
|
copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
|
||||||
|
priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
|
||||||
|
|
||||||
return priv, nil
|
return priv, nil
|
||||||
}
|
}
|
||||||
31
vendor/github.com/google/certificate-transparency-go/x509/test-dir.crt
generated
vendored
Normal file
31
vendor/github.com/google/certificate-transparency-go/x509/test-dir.crt
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
|
||||||
|
BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
|
||||||
|
dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz
|
||||||
|
NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV
|
||||||
|
BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM
|
||||||
|
WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu
|
||||||
|
XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql
|
||||||
|
MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN
|
||||||
|
hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF
|
||||||
|
k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk
|
||||||
|
+oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM
|
||||||
|
uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY
|
||||||
|
adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2
|
||||||
|
cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio
|
||||||
|
9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui
|
||||||
|
dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD
|
||||||
|
VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe
|
||||||
|
xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3
|
||||||
|
ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC
|
||||||
|
6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc
|
||||||
|
g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT
|
||||||
|
Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
|
||||||
|
3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA
|
||||||
|
m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W
|
||||||
|
PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC
|
||||||
|
Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M
|
||||||
|
JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
32
vendor/github.com/google/certificate-transparency-go/x509/test-file.crt
generated
vendored
Normal file
32
vendor/github.com/google/certificate-transparency-go/x509/test-file.crt
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
|
||||||
|
BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
|
||||||
|
dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy
|
||||||
|
MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD
|
||||||
|
VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs
|
||||||
|
i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW
|
||||||
|
jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI
|
||||||
|
KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St
|
||||||
|
cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj
|
||||||
|
iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw
|
||||||
|
5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03
|
||||||
|
Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv
|
||||||
|
8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN
|
||||||
|
fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A
|
||||||
|
GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft
|
||||||
|
C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf
|
||||||
|
BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx
|
||||||
|
AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK
|
||||||
|
SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake
|
||||||
|
pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT
|
||||||
|
xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl
|
||||||
|
r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls
|
||||||
|
BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd
|
||||||
|
4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+
|
||||||
|
75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p
|
||||||
|
z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc
|
||||||
|
rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG
|
||||||
|
vQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
1035
vendor/github.com/google/certificate-transparency-go/x509/verify.go
generated
vendored
Normal file
1035
vendor/github.com/google/certificate-transparency-go/x509/verify.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2841
vendor/github.com/google/certificate-transparency-go/x509/x509.go
generated
vendored
Normal file
2841
vendor/github.com/google/certificate-transparency-go/x509/x509.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
55
vendor/github.com/google/certificate-transparency-go/x509/x509_test_import.go
generated
vendored
Normal file
55
vendor/github.com/google/certificate-transparency-go/x509/x509_test_import.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
// This file is run by the x509 tests to ensure that a program with minimal
|
||||||
|
// imports can sign certificates without errors resulting from missing hash
|
||||||
|
// functions.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
// START CT CHANGES
|
||||||
|
"github.com/google/certificate-transparency-go/x509"
|
||||||
|
"github.com/google/certificate-transparency-go/x509/pkix"
|
||||||
|
// END CT CHANGES
|
||||||
|
"encoding/pem"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
block, _ := pem.Decode([]byte(pemPrivateKey))
|
||||||
|
rsaPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to parse private key: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(1),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "test",
|
||||||
|
Organization: []string{"Σ Acme Co"},
|
||||||
|
},
|
||||||
|
NotBefore: time.Unix(1000, 0),
|
||||||
|
NotAfter: time.Unix(100000, 0),
|
||||||
|
KeyUsage: x509.KeyUsageCertSign,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = x509.CreateCertificate(rand.Reader, &template, &template, &rsaPriv.PublicKey, rsaPriv); err != nil {
|
||||||
|
panic("failed to create certificate with basic imports: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
|
||||||
|
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
|
||||||
|
/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
|
||||||
|
RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
|
||||||
|
EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
|
||||||
|
IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
|
||||||
|
tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
`
|
||||||
32
vendor/github.com/google/certificate-transparency/go/BUILD
generated
vendored
32
vendor/github.com/google/certificate-transparency/go/BUILD
generated
vendored
@@ -1,32 +0,0 @@
|
|||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"serialization.go",
|
|
||||||
"signatures.go",
|
|
||||||
"types.go",
|
|
||||||
],
|
|
||||||
importpath = "github.com/google/certificate-transparency/go",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = ["//vendor/github.com/google/certificate-transparency/go/x509:go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [
|
|
||||||
":package-srcs",
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/asn1:all-srcs",
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/client:all-srcs",
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/x509:all-srcs",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
25
vendor/github.com/google/certificate-transparency/go/README.md
generated
vendored
25
vendor/github.com/google/certificate-transparency/go/README.md
generated
vendored
@@ -1,25 +0,0 @@
|
|||||||
This is the really early beginnings of a certificate transparency log
|
|
||||||
client written in Go, along with a log scanner tool.
|
|
||||||
|
|
||||||
You'll need go v1.1 or higher to compile.
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
This go code must be imported into your go workspace before you can
|
|
||||||
use it, which can be done with:
|
|
||||||
|
|
||||||
go get github.com/google/certificate-transparency/go/client
|
|
||||||
go get github.com/google/certificate-transparency/go/scanner
|
|
||||||
etc.
|
|
||||||
|
|
||||||
# Building the binaries
|
|
||||||
|
|
||||||
To compile the log scanner run:
|
|
||||||
|
|
||||||
go build github.com/google/certificate-transparency/go/scanner/main/scanner.go
|
|
||||||
|
|
||||||
# Contributing
|
|
||||||
|
|
||||||
When sending pull requests, please ensure that everything's been run
|
|
||||||
through ```gofmt``` beforehand so we can keep everything nice and
|
|
||||||
tidy.
|
|
||||||
581
vendor/github.com/google/certificate-transparency/go/asn1/marshal.go
generated
vendored
581
vendor/github.com/google/certificate-transparency/go/asn1/marshal.go
generated
vendored
@@ -1,581 +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 LICENSE file.
|
|
||||||
|
|
||||||
package asn1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A forkableWriter is an in-memory buffer that can be
|
|
||||||
// 'forked' to create new forkableWriters that bracket the
|
|
||||||
// original. After
|
|
||||||
// pre, post := w.fork();
|
|
||||||
// the overall sequence of bytes represented is logically w+pre+post.
|
|
||||||
type forkableWriter struct {
|
|
||||||
*bytes.Buffer
|
|
||||||
pre, post *forkableWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func newForkableWriter() *forkableWriter {
|
|
||||||
return &forkableWriter{new(bytes.Buffer), nil, nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *forkableWriter) fork() (pre, post *forkableWriter) {
|
|
||||||
if f.pre != nil || f.post != nil {
|
|
||||||
panic("have already forked")
|
|
||||||
}
|
|
||||||
f.pre = newForkableWriter()
|
|
||||||
f.post = newForkableWriter()
|
|
||||||
return f.pre, f.post
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *forkableWriter) Len() (l int) {
|
|
||||||
l += f.Buffer.Len()
|
|
||||||
if f.pre != nil {
|
|
||||||
l += f.pre.Len()
|
|
||||||
}
|
|
||||||
if f.post != nil {
|
|
||||||
l += f.post.Len()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
|
|
||||||
n, err = out.Write(f.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var nn int
|
|
||||||
|
|
||||||
if f.pre != nil {
|
|
||||||
nn, err = f.pre.writeTo(out)
|
|
||||||
n += nn
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.post != nil {
|
|
||||||
nn, err = f.post.writeTo(out)
|
|
||||||
n += nn
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalBase128Int(out *forkableWriter, n int64) (err error) {
|
|
||||||
if n == 0 {
|
|
||||||
err = out.WriteByte(0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l := 0
|
|
||||||
for i := n; i > 0; i >>= 7 {
|
|
||||||
l++
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := l - 1; i >= 0; i-- {
|
|
||||||
o := byte(n >> uint(i*7))
|
|
||||||
o &= 0x7f
|
|
||||||
if i != 0 {
|
|
||||||
o |= 0x80
|
|
||||||
}
|
|
||||||
err = out.WriteByte(o)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalInt64(out *forkableWriter, i int64) (err error) {
|
|
||||||
n := int64Length(i)
|
|
||||||
|
|
||||||
for ; n > 0; n-- {
|
|
||||||
err = out.WriteByte(byte(i >> uint((n-1)*8)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func int64Length(i int64) (numBytes int) {
|
|
||||||
numBytes = 1
|
|
||||||
|
|
||||||
for i > 127 {
|
|
||||||
numBytes++
|
|
||||||
i >>= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
for i < -128 {
|
|
||||||
numBytes++
|
|
||||||
i >>= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
|
|
||||||
if n.Sign() < 0 {
|
|
||||||
// A negative number has to be converted to two's-complement
|
|
||||||
// form. So we'll subtract 1 and invert. If the
|
|
||||||
// most-significant-bit isn't set then we'll need to pad the
|
|
||||||
// beginning with 0xff in order to keep the number negative.
|
|
||||||
nMinus1 := new(big.Int).Neg(n)
|
|
||||||
nMinus1.Sub(nMinus1, bigOne)
|
|
||||||
bytes := nMinus1.Bytes()
|
|
||||||
for i := range bytes {
|
|
||||||
bytes[i] ^= 0xff
|
|
||||||
}
|
|
||||||
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
|
|
||||||
err = out.WriteByte(0xff)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, err = out.Write(bytes)
|
|
||||||
} else if n.Sign() == 0 {
|
|
||||||
// Zero is written as a single 0 zero rather than no bytes.
|
|
||||||
err = out.WriteByte(0x00)
|
|
||||||
} else {
|
|
||||||
bytes := n.Bytes()
|
|
||||||
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
|
|
||||||
// We'll have to pad this with 0x00 in order to stop it
|
|
||||||
// looking like a negative number.
|
|
||||||
err = out.WriteByte(0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, err = out.Write(bytes)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalLength(out *forkableWriter, i int) (err error) {
|
|
||||||
n := lengthLength(i)
|
|
||||||
|
|
||||||
for ; n > 0; n-- {
|
|
||||||
err = out.WriteByte(byte(i >> uint((n-1)*8)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lengthLength(i int) (numBytes int) {
|
|
||||||
numBytes = 1
|
|
||||||
for i > 255 {
|
|
||||||
numBytes++
|
|
||||||
i >>= 8
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
|
|
||||||
b := uint8(t.class) << 6
|
|
||||||
if t.isCompound {
|
|
||||||
b |= 0x20
|
|
||||||
}
|
|
||||||
if t.tag >= 31 {
|
|
||||||
b |= 0x1f
|
|
||||||
err = out.WriteByte(b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = marshalBase128Int(out, int64(t.tag))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
b |= uint8(t.tag)
|
|
||||||
err = out.WriteByte(b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.length >= 128 {
|
|
||||||
l := lengthLength(t.length)
|
|
||||||
err = out.WriteByte(0x80 | byte(l))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = marshalLength(out, t.length)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = out.WriteByte(byte(t.length))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalBitString(out *forkableWriter, b BitString) (err error) {
|
|
||||||
paddingBits := byte((8 - b.BitLength%8) % 8)
|
|
||||||
err = out.WriteByte(paddingBits)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = out.Write(b.Bytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalObjectIdentifier(out *forkableWriter, oid []int) (err error) {
|
|
||||||
if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
|
|
||||||
return StructuralError{"invalid object identifier"}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalBase128Int(out, int64(oid[0]*40+oid[1]))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 2; i < len(oid); i++ {
|
|
||||||
err = marshalBase128Int(out, int64(oid[i]))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalPrintableString(out *forkableWriter, s string) (err error) {
|
|
||||||
b := []byte(s)
|
|
||||||
for _, c := range b {
|
|
||||||
if !isPrintable(c) {
|
|
||||||
return StructuralError{"PrintableString contains invalid character"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = out.Write(b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalIA5String(out *forkableWriter, s string) (err error) {
|
|
||||||
b := []byte(s)
|
|
||||||
for _, c := range b {
|
|
||||||
if c > 127 {
|
|
||||||
return StructuralError{"IA5String contains invalid character"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = out.Write(b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalUTF8String(out *forkableWriter, s string) (err error) {
|
|
||||||
_, err = out.Write([]byte(s))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalTwoDigits(out *forkableWriter, v int) (err error) {
|
|
||||||
err = out.WriteByte(byte('0' + (v/10)%10))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return out.WriteByte(byte('0' + v%10))
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
|
|
||||||
year, month, day := t.Date()
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case 1950 <= year && year < 2000:
|
|
||||||
err = marshalTwoDigits(out, int(year-1900))
|
|
||||||
case 2000 <= year && year < 2050:
|
|
||||||
err = marshalTwoDigits(out, int(year-2000))
|
|
||||||
default:
|
|
||||||
return StructuralError{"cannot represent time as UTCTime"}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, int(month))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, day)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hour, min, sec := t.Clock()
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, hour)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, min)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, sec)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, offset := t.Zone()
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case offset/60 == 0:
|
|
||||||
err = out.WriteByte('Z')
|
|
||||||
return
|
|
||||||
case offset > 0:
|
|
||||||
err = out.WriteByte('+')
|
|
||||||
case offset < 0:
|
|
||||||
err = out.WriteByte('-')
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
offsetMinutes := offset / 60
|
|
||||||
if offsetMinutes < 0 {
|
|
||||||
offsetMinutes = -offsetMinutes
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, offsetMinutes/60)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTwoDigits(out, offsetMinutes%60)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func stripTagAndLength(in []byte) []byte {
|
|
||||||
_, offset, err := parseTagAndLength(in, 0)
|
|
||||||
if err != nil {
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
return in[offset:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
|
|
||||||
switch value.Type() {
|
|
||||||
case timeType:
|
|
||||||
return marshalUTCTime(out, value.Interface().(time.Time))
|
|
||||||
case bitStringType:
|
|
||||||
return marshalBitString(out, value.Interface().(BitString))
|
|
||||||
case objectIdentifierType:
|
|
||||||
return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
|
|
||||||
case bigIntType:
|
|
||||||
return marshalBigInt(out, value.Interface().(*big.Int))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := value; v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
if v.Bool() {
|
|
||||||
return out.WriteByte(255)
|
|
||||||
} else {
|
|
||||||
return out.WriteByte(0)
|
|
||||||
}
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return marshalInt64(out, int64(v.Int()))
|
|
||||||
case reflect.Struct:
|
|
||||||
t := v.Type()
|
|
||||||
|
|
||||||
startingField := 0
|
|
||||||
|
|
||||||
// If the first element of the structure is a non-empty
|
|
||||||
// RawContents, then we don't bother serializing the rest.
|
|
||||||
if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
|
|
||||||
s := v.Field(0)
|
|
||||||
if s.Len() > 0 {
|
|
||||||
bytes := make([]byte, s.Len())
|
|
||||||
for i := 0; i < s.Len(); i++ {
|
|
||||||
bytes[i] = uint8(s.Index(i).Uint())
|
|
||||||
}
|
|
||||||
/* The RawContents will contain the tag and
|
|
||||||
* length fields but we'll also be writing
|
|
||||||
* those ourselves, so we strip them out of
|
|
||||||
* bytes */
|
|
||||||
_, err = out.Write(stripTagAndLength(bytes))
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
startingField = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := startingField; i < t.NumField(); i++ {
|
|
||||||
var pre *forkableWriter
|
|
||||||
pre, out = out.fork()
|
|
||||||
err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case reflect.Slice:
|
|
||||||
sliceType := v.Type()
|
|
||||||
if sliceType.Elem().Kind() == reflect.Uint8 {
|
|
||||||
bytes := make([]byte, v.Len())
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
bytes[i] = uint8(v.Index(i).Uint())
|
|
||||||
}
|
|
||||||
_, err = out.Write(bytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var fp fieldParameters
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
var pre *forkableWriter
|
|
||||||
pre, out = out.fork()
|
|
||||||
err = marshalField(pre, v.Index(i), fp)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case reflect.String:
|
|
||||||
switch params.stringType {
|
|
||||||
case tagIA5String:
|
|
||||||
return marshalIA5String(out, v.String())
|
|
||||||
case tagPrintableString:
|
|
||||||
return marshalPrintableString(out, v.String())
|
|
||||||
default:
|
|
||||||
return marshalUTF8String(out, v.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return StructuralError{"unknown Go type"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
|
|
||||||
// If the field is an interface{} then recurse into it.
|
|
||||||
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
|
|
||||||
return marshalField(out, v.Elem(), params)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Type() == rawValueType {
|
|
||||||
rv := v.Interface().(RawValue)
|
|
||||||
if len(rv.FullBytes) != 0 {
|
|
||||||
_, err = out.Write(rv.FullBytes)
|
|
||||||
} else {
|
|
||||||
err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = out.Write(rv.Bytes)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tag, isCompound, ok := getUniversalType(v.Type())
|
|
||||||
if !ok {
|
|
||||||
err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
class := classUniversal
|
|
||||||
|
|
||||||
if params.stringType != 0 && tag != tagPrintableString {
|
|
||||||
return StructuralError{"explicit string type given to non-string member"}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tag == tagPrintableString {
|
|
||||||
if params.stringType == 0 {
|
|
||||||
// This is a string without an explicit string type. We'll use
|
|
||||||
// a PrintableString if the character set in the string is
|
|
||||||
// sufficiently limited, otherwise we'll use a UTF8String.
|
|
||||||
for _, r := range v.String() {
|
|
||||||
if r >= utf8.RuneSelf || !isPrintable(byte(r)) {
|
|
||||||
if !utf8.ValidString(v.String()) {
|
|
||||||
return errors.New("asn1: string not valid UTF-8")
|
|
||||||
}
|
|
||||||
tag = tagUTF8String
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tag = params.stringType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.set {
|
|
||||||
if tag != tagSequence {
|
|
||||||
return StructuralError{"non sequence tagged as set"}
|
|
||||||
}
|
|
||||||
tag = tagSet
|
|
||||||
}
|
|
||||||
|
|
||||||
tags, body := out.fork()
|
|
||||||
|
|
||||||
err = marshalBody(body, v, params)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyLen := body.Len()
|
|
||||||
|
|
||||||
var explicitTag *forkableWriter
|
|
||||||
if params.explicit {
|
|
||||||
explicitTag, tags = tags.fork()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !params.explicit && params.tag != nil {
|
|
||||||
// implicit tag.
|
|
||||||
tag = *params.tag
|
|
||||||
class = classContextSpecific
|
|
||||||
}
|
|
||||||
|
|
||||||
err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.explicit {
|
|
||||||
err = marshalTagAndLength(explicitTag, tagAndLength{
|
|
||||||
class: classContextSpecific,
|
|
||||||
tag: *params.tag,
|
|
||||||
length: bodyLen + tags.Len(),
|
|
||||||
isCompound: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal returns the ASN.1 encoding of val.
|
|
||||||
func Marshal(val interface{}) ([]byte, error) {
|
|
||||||
var out bytes.Buffer
|
|
||||||
v := reflect.ValueOf(val)
|
|
||||||
f := newForkableWriter()
|
|
||||||
err := marshalField(f, v, fieldParameters{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = f.writeTo(&out)
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
||||||
358
vendor/github.com/google/certificate-transparency/go/client/logclient.go
generated
vendored
358
vendor/github.com/google/certificate-transparency/go/client/logclient.go
generated
vendored
@@ -1,358 +0,0 @@
|
|||||||
// Package client is a CT log client implementation and contains types and code
|
|
||||||
// for interacting with RFC6962-compliant CT Log instances.
|
|
||||||
// See http://tools.ietf.org/html/rfc6962 for details
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/certificate-transparency/go"
|
|
||||||
"github.com/mreiferson/go-httpclient"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// URI paths for CT Log endpoints
|
|
||||||
const (
|
|
||||||
AddChainPath = "/ct/v1/add-chain"
|
|
||||||
AddPreChainPath = "/ct/v1/add-pre-chain"
|
|
||||||
GetSTHPath = "/ct/v1/get-sth"
|
|
||||||
GetEntriesPath = "/ct/v1/get-entries"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogClient represents a client for a given CT Log instance
|
|
||||||
type LogClient struct {
|
|
||||||
uri string // the base URI of the log. e.g. http://ct.googleapis/pilot
|
|
||||||
httpClient *http.Client // used to interact with the log via HTTP
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// JSON structures follow.
|
|
||||||
// These represent the structures returned by the CT Log server.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// addChainRequest represents the JSON request body sent to the add-chain CT
|
|
||||||
// method.
|
|
||||||
type addChainRequest struct {
|
|
||||||
Chain []string `json:"chain"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// addChainResponse represents the JSON response to the add-chain CT method.
|
|
||||||
// An SCT represents a Log's promise to integrate a [pre-]certificate into the
|
|
||||||
// log within a defined period of time.
|
|
||||||
type addChainResponse struct {
|
|
||||||
SCTVersion ct.Version `json:"sct_version"` // SCT structure version
|
|
||||||
ID string `json:"id"` // Log ID
|
|
||||||
Timestamp uint64 `json:"timestamp"` // Timestamp of issuance
|
|
||||||
Extensions string `json:"extensions"` // Holder for any CT extensions
|
|
||||||
Signature string `json:"signature"` // Log signature for this SCT
|
|
||||||
}
|
|
||||||
|
|
||||||
// getSTHResponse respresents the JSON response to the get-sth CT method
|
|
||||||
type getSTHResponse struct {
|
|
||||||
TreeSize uint64 `json:"tree_size"` // Number of certs in the current tree
|
|
||||||
Timestamp uint64 `json:"timestamp"` // Time that the tree was created
|
|
||||||
SHA256RootHash string `json:"sha256_root_hash"` // Root hash of the tree
|
|
||||||
TreeHeadSignature string `json:"tree_head_signature"` // Log signature for this STH
|
|
||||||
}
|
|
||||||
|
|
||||||
// base64LeafEntry respresents a Base64 encoded leaf entry
|
|
||||||
type base64LeafEntry struct {
|
|
||||||
LeafInput string `json:"leaf_input"`
|
|
||||||
ExtraData string `json:"extra_data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEntriesReponse respresents the JSON response to the CT get-entries method
|
|
||||||
type getEntriesResponse struct {
|
|
||||||
Entries []base64LeafEntry `json:"entries"` // the list of returned entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// getConsistencyProofResponse represents the JSON response to the CT get-consistency-proof method
|
|
||||||
type getConsistencyProofResponse struct {
|
|
||||||
Consistency []string `json:"consistency"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAuditProofResponse represents the JSON response to the CT get-audit-proof method
|
|
||||||
type getAuditProofResponse struct {
|
|
||||||
Hash []string `json:"hash"` // the hashes which make up the proof
|
|
||||||
TreeSize uint64 `json:"tree_size"` // the tree size against which this proof is constructed
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAcceptedRootsResponse represents the JSON response to the CT get-roots method.
|
|
||||||
type getAcceptedRootsResponse struct {
|
|
||||||
Certificates []string `json:"certificates"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEntryAndProodReponse represents the JSON response to the CT get-entry-and-proof method
|
|
||||||
type getEntryAndProofResponse struct {
|
|
||||||
LeafInput string `json:"leaf_input"` // the entry itself
|
|
||||||
ExtraData string `json:"extra_data"` // any chain provided when the entry was added to the log
|
|
||||||
AuditPath []string `json:"audit_path"` // the corresponding proof
|
|
||||||
}
|
|
||||||
|
|
||||||
// New constructs a new LogClient instance.
|
|
||||||
// |uri| is the base URI of the CT log instance to interact with, e.g.
|
|
||||||
// http://ct.googleapis.com/pilot
|
|
||||||
func New(uri string) *LogClient {
|
|
||||||
var c LogClient
|
|
||||||
c.uri = uri
|
|
||||||
transport := &httpclient.Transport{
|
|
||||||
ConnectTimeout: 10 * time.Second,
|
|
||||||
RequestTimeout: 30 * time.Second,
|
|
||||||
ResponseHeaderTimeout: 30 * time.Second,
|
|
||||||
MaxIdleConnsPerHost: 10,
|
|
||||||
DisableKeepAlives: false,
|
|
||||||
}
|
|
||||||
c.httpClient = &http.Client{Transport: transport}
|
|
||||||
return &c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Makes a HTTP call to |uri|, and attempts to parse the response as a JSON
|
|
||||||
// representation of the structure in |res|.
|
|
||||||
// Returns a non-nil |error| if there was a problem.
|
|
||||||
func (c *LogClient) fetchAndParse(uri string, res interface{}) error {
|
|
||||||
req, err := http.NewRequest("GET", uri, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.Header.Set("Keep-Alive", "timeout=15, max=100")
|
|
||||||
resp, err := c.httpClient.Do(req)
|
|
||||||
var body []byte
|
|
||||||
if resp != nil {
|
|
||||||
body, err = ioutil.ReadAll(resp.Body)
|
|
||||||
resp.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(body, &res); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Makes a HTTP POST call to |uri|, and attempts to parse the response as a JSON
|
|
||||||
// representation of the structure in |res|.
|
|
||||||
// Returns a non-nil |error| if there was a problem.
|
|
||||||
func (c *LogClient) postAndParse(uri string, req interface{}, res interface{}) (*http.Response, string, error) {
|
|
||||||
postBody, err := json.Marshal(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
httpReq, err := http.NewRequest("POST", uri, bytes.NewReader(postBody))
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
httpReq.Header.Set("Keep-Alive", "timeout=15, max=100")
|
|
||||||
httpReq.Header.Set("Content-Type", "application/json")
|
|
||||||
resp, err := c.httpClient.Do(httpReq)
|
|
||||||
// Read all of the body, if there is one, so that the http.Client can do
|
|
||||||
// Keep-Alive:
|
|
||||||
var body []byte
|
|
||||||
if resp != nil {
|
|
||||||
body, err = ioutil.ReadAll(resp.Body)
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return resp, string(body), err
|
|
||||||
}
|
|
||||||
if resp.StatusCode == 200 {
|
|
||||||
if err != nil {
|
|
||||||
return resp, string(body), err
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(body, &res); err != nil {
|
|
||||||
return resp, string(body), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp, string(body), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func backoffForRetry(ctx context.Context, d time.Duration) error {
|
|
||||||
backoffTimer := time.NewTimer(d)
|
|
||||||
if ctx != nil {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
case <-backoffTimer.C:
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
<-backoffTimer.C
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to add |chain| to the log, using the api end-point specified by
|
|
||||||
// |path|. If provided context expires before submission is complete an
|
|
||||||
// error will be returned.
|
|
||||||
func (c *LogClient) addChainWithRetry(ctx context.Context, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
|
||||||
var resp addChainResponse
|
|
||||||
var req addChainRequest
|
|
||||||
for _, link := range chain {
|
|
||||||
req.Chain = append(req.Chain, base64.StdEncoding.EncodeToString(link))
|
|
||||||
}
|
|
||||||
httpStatus := "Unknown"
|
|
||||||
backoffSeconds := 0
|
|
||||||
done := false
|
|
||||||
for !done {
|
|
||||||
if backoffSeconds > 0 {
|
|
||||||
log.Printf("Got %s, backing-off %d seconds", httpStatus, backoffSeconds)
|
|
||||||
}
|
|
||||||
err := backoffForRetry(ctx, time.Second*time.Duration(backoffSeconds))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if backoffSeconds > 0 {
|
|
||||||
backoffSeconds = 0
|
|
||||||
}
|
|
||||||
httpResp, errorBody, err := c.postAndParse(c.uri+path, &req, &resp)
|
|
||||||
if err != nil {
|
|
||||||
backoffSeconds = 10
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case httpResp.StatusCode == 200:
|
|
||||||
done = true
|
|
||||||
case httpResp.StatusCode == 408:
|
|
||||||
// request timeout, retry immediately
|
|
||||||
case httpResp.StatusCode == 503:
|
|
||||||
// Retry
|
|
||||||
backoffSeconds = 10
|
|
||||||
if retryAfter := httpResp.Header.Get("Retry-After"); retryAfter != "" {
|
|
||||||
if seconds, err := strconv.Atoi(retryAfter); err == nil {
|
|
||||||
backoffSeconds = seconds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("got HTTP Status %s: %s", httpResp.Status, errorBody)
|
|
||||||
}
|
|
||||||
httpStatus = httpResp.Status
|
|
||||||
}
|
|
||||||
|
|
||||||
rawLogID, err := base64.StdEncoding.DecodeString(resp.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rawSignature, err := base64.StdEncoding.DecodeString(resp.Signature)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ds, err := ct.UnmarshalDigitallySigned(bytes.NewReader(rawSignature))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var logID ct.SHA256Hash
|
|
||||||
copy(logID[:], rawLogID)
|
|
||||||
return &ct.SignedCertificateTimestamp{
|
|
||||||
SCTVersion: resp.SCTVersion,
|
|
||||||
LogID: logID,
|
|
||||||
Timestamp: resp.Timestamp,
|
|
||||||
Extensions: ct.CTExtensions(resp.Extensions),
|
|
||||||
Signature: *ds}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddChain adds the (DER represented) X509 |chain| to the log.
|
|
||||||
func (c *LogClient) AddChain(chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
|
||||||
return c.addChainWithRetry(nil, AddChainPath, chain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddPreChain adds the (DER represented) Precertificate |chain| to the log.
|
|
||||||
func (c *LogClient) AddPreChain(chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
|
||||||
return c.addChainWithRetry(nil, AddPreChainPath, chain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddChainWithContext adds the (DER represented) X509 |chain| to the log and
|
|
||||||
// fails if the provided context expires before the chain is submitted.
|
|
||||||
func (c *LogClient) AddChainWithContext(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
|
||||||
return c.addChainWithRetry(ctx, AddChainPath, chain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSTH retrieves the current STH from the log.
|
|
||||||
// Returns a populated SignedTreeHead, or a non-nil error.
|
|
||||||
func (c *LogClient) GetSTH() (sth *ct.SignedTreeHead, err error) {
|
|
||||||
var resp getSTHResponse
|
|
||||||
if err = c.fetchAndParse(c.uri+GetSTHPath, &resp); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sth = &ct.SignedTreeHead{
|
|
||||||
TreeSize: resp.TreeSize,
|
|
||||||
Timestamp: resp.Timestamp,
|
|
||||||
}
|
|
||||||
|
|
||||||
rawRootHash, err := base64.StdEncoding.DecodeString(resp.SHA256RootHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid base64 encoding in sha256_root_hash: %v", err)
|
|
||||||
}
|
|
||||||
if len(rawRootHash) != sha256.Size {
|
|
||||||
return nil, fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(rawRootHash))
|
|
||||||
}
|
|
||||||
copy(sth.SHA256RootHash[:], rawRootHash)
|
|
||||||
|
|
||||||
rawSignature, err := base64.StdEncoding.DecodeString(resp.TreeHeadSignature)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("invalid base64 encoding in tree_head_signature")
|
|
||||||
}
|
|
||||||
ds, err := ct.UnmarshalDigitallySigned(bytes.NewReader(rawSignature))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// TODO(alcutter): Verify signature
|
|
||||||
sth.TreeHeadSignature = *ds
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetEntries attempts to retrieve the entries in the sequence [|start|, |end|] from the CT
|
|
||||||
// log server. (see section 4.6.)
|
|
||||||
// Returns a slice of LeafInputs or a non-nil error.
|
|
||||||
func (c *LogClient) GetEntries(start, end int64) ([]ct.LogEntry, error) {
|
|
||||||
if end < 0 {
|
|
||||||
return nil, errors.New("end should be >= 0")
|
|
||||||
}
|
|
||||||
if end < start {
|
|
||||||
return nil, errors.New("start should be <= end")
|
|
||||||
}
|
|
||||||
var resp getEntriesResponse
|
|
||||||
err := c.fetchAndParse(fmt.Sprintf("%s%s?start=%d&end=%d", c.uri, GetEntriesPath, start, end), &resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entries := make([]ct.LogEntry, len(resp.Entries))
|
|
||||||
for index, entry := range resp.Entries {
|
|
||||||
leafBytes, err := base64.StdEncoding.DecodeString(entry.LeafInput)
|
|
||||||
leaf, err := ct.ReadMerkleTreeLeaf(bytes.NewBuffer(leafBytes))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entries[index].Leaf = *leaf
|
|
||||||
chainBytes, err := base64.StdEncoding.DecodeString(entry.ExtraData)
|
|
||||||
|
|
||||||
var chain []ct.ASN1Cert
|
|
||||||
switch leaf.TimestampedEntry.EntryType {
|
|
||||||
case ct.X509LogEntryType:
|
|
||||||
chain, err = ct.UnmarshalX509ChainArray(chainBytes)
|
|
||||||
|
|
||||||
case ct.PrecertLogEntryType:
|
|
||||||
chain, err = ct.UnmarshalPrecertChainArray(chainBytes)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("saw unknown entry type: %v", leaf.TimestampedEntry.EntryType)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entries[index].Chain = chain
|
|
||||||
entries[index].Index = start + int64(index)
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
512
vendor/github.com/google/certificate-transparency/go/serialization.go
generated
vendored
512
vendor/github.com/google/certificate-transparency/go/serialization.go
generated
vendored
@@ -1,512 +0,0 @@
|
|||||||
package ct
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"container/list"
|
|
||||||
"crypto"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Variable size structure prefix-header byte lengths
|
|
||||||
const (
|
|
||||||
CertificateLengthBytes = 3
|
|
||||||
PreCertificateLengthBytes = 3
|
|
||||||
ExtensionsLengthBytes = 2
|
|
||||||
CertificateChainLengthBytes = 3
|
|
||||||
SignatureLengthBytes = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Max lengths
|
|
||||||
const (
|
|
||||||
MaxCertificateLength = (1 << 24) - 1
|
|
||||||
MaxExtensionsLength = (1 << 16) - 1
|
|
||||||
)
|
|
||||||
|
|
||||||
func writeUint(w io.Writer, value uint64, numBytes int) error {
|
|
||||||
buf := make([]uint8, numBytes)
|
|
||||||
for i := 0; i < numBytes; i++ {
|
|
||||||
buf[numBytes-i-1] = uint8(value & 0xff)
|
|
||||||
value >>= 8
|
|
||||||
}
|
|
||||||
if value != 0 {
|
|
||||||
return errors.New("numBytes was insufficiently large to represent value")
|
|
||||||
}
|
|
||||||
if _, err := w.Write(buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeVarBytes(w io.Writer, value []byte, numLenBytes int) error {
|
|
||||||
if err := writeUint(w, uint64(len(value)), numLenBytes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := w.Write(value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readUint(r io.Reader, numBytes int) (uint64, error) {
|
|
||||||
var l uint64
|
|
||||||
for i := 0; i < numBytes; i++ {
|
|
||||||
l <<= 8
|
|
||||||
var t uint8
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &t); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
l |= uint64(t)
|
|
||||||
}
|
|
||||||
return l, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a variable length array of bytes from |r|. |numLenBytes| specifies the
|
|
||||||
// number of (BigEndian) prefix-bytes which contain the length of the actual
|
|
||||||
// array data bytes that follow.
|
|
||||||
// Allocates an array to hold the contents and returns a slice view into it if
|
|
||||||
// the read was successful, or an error otherwise.
|
|
||||||
func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
|
|
||||||
switch {
|
|
||||||
case numLenBytes > 8:
|
|
||||||
return nil, fmt.Errorf("numLenBytes too large (%d)", numLenBytes)
|
|
||||||
case numLenBytes == 0:
|
|
||||||
return nil, errors.New("numLenBytes should be > 0")
|
|
||||||
}
|
|
||||||
l, err := readUint(r, numLenBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
data := make([]byte, l)
|
|
||||||
n, err := r.Read(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n != int(l) {
|
|
||||||
return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a list of ASN1Cert types from |r|
|
|
||||||
func readASN1CertList(r io.Reader, totalLenBytes int, elementLenBytes int) ([]ASN1Cert, error) {
|
|
||||||
listBytes, err := readVarBytes(r, totalLenBytes)
|
|
||||||
if err != nil {
|
|
||||||
return []ASN1Cert{}, err
|
|
||||||
}
|
|
||||||
list := list.New()
|
|
||||||
listReader := bytes.NewReader(listBytes)
|
|
||||||
var entry []byte
|
|
||||||
for err == nil {
|
|
||||||
entry, err = readVarBytes(listReader, elementLenBytes)
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
return []ASN1Cert{}, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.PushBack(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret := make([]ASN1Cert, list.Len())
|
|
||||||
i := 0
|
|
||||||
for e := list.Front(); e != nil; e = e.Next() {
|
|
||||||
ret[i] = e.Value.([]byte)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadTimestampedEntryInto parses the byte-stream representation of a
|
|
||||||
// TimestampedEntry from |r| and populates the struct |t| with the data. See
|
|
||||||
// RFC section 3.4 for details on the format.
|
|
||||||
// Returns a non-nil error if there was a problem.
|
|
||||||
func ReadTimestampedEntryInto(r io.Reader, t *TimestampedEntry) error {
|
|
||||||
var err error
|
|
||||||
if err = binary.Read(r, binary.BigEndian, &t.Timestamp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = binary.Read(r, binary.BigEndian, &t.EntryType); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch t.EntryType {
|
|
||||||
case X509LogEntryType:
|
|
||||||
if t.X509Entry, err = readVarBytes(r, CertificateLengthBytes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case PrecertLogEntryType:
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &t.PrecertEntry.IssuerKeyHash); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if t.PrecertEntry.TBSCertificate, err = readVarBytes(r, PreCertificateLengthBytes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown EntryType: %d", t.EntryType)
|
|
||||||
}
|
|
||||||
t.Extensions, err = readVarBytes(r, ExtensionsLengthBytes)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadMerkleTreeLeaf parses the byte-stream representation of a MerkleTreeLeaf
|
|
||||||
// and returns a pointer to a new MerkleTreeLeaf structure containing the
|
|
||||||
// parsed data.
|
|
||||||
// See RFC section 3.4 for details on the format.
|
|
||||||
// Returns a pointer to a new MerkleTreeLeaf or non-nil error if there was a
|
|
||||||
// problem
|
|
||||||
func ReadMerkleTreeLeaf(r io.Reader) (*MerkleTreeLeaf, error) {
|
|
||||||
var m MerkleTreeLeaf
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &m.Version); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if m.Version != V1 {
|
|
||||||
return nil, fmt.Errorf("unknown Version %d", m.Version)
|
|
||||||
}
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &m.LeafType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if m.LeafType != TimestampedEntryLeafType {
|
|
||||||
return nil, fmt.Errorf("unknown LeafType %d", m.LeafType)
|
|
||||||
}
|
|
||||||
if err := ReadTimestampedEntryInto(r, &m.TimestampedEntry); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalX509ChainArray unmarshalls the contents of the "chain:" entry in a
|
|
||||||
// GetEntries response in the case where the entry refers to an X509 leaf.
|
|
||||||
func UnmarshalX509ChainArray(b []byte) ([]ASN1Cert, error) {
|
|
||||||
return readASN1CertList(bytes.NewReader(b), CertificateChainLengthBytes, CertificateLengthBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalPrecertChainArray unmarshalls the contents of the "chain:" entry in
|
|
||||||
// a GetEntries response in the case where the entry refers to a Precertificate
|
|
||||||
// leaf.
|
|
||||||
func UnmarshalPrecertChainArray(b []byte) ([]ASN1Cert, error) {
|
|
||||||
var chain []ASN1Cert
|
|
||||||
|
|
||||||
reader := bytes.NewReader(b)
|
|
||||||
// read the pre-cert entry:
|
|
||||||
precert, err := readVarBytes(reader, CertificateLengthBytes)
|
|
||||||
if err != nil {
|
|
||||||
return chain, err
|
|
||||||
}
|
|
||||||
chain = append(chain, precert)
|
|
||||||
// and then read and return the chain up to the root:
|
|
||||||
remainingChain, err := readASN1CertList(reader, CertificateChainLengthBytes, CertificateLengthBytes)
|
|
||||||
if err != nil {
|
|
||||||
return chain, err
|
|
||||||
}
|
|
||||||
chain = append(chain, remainingChain...)
|
|
||||||
return chain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalDigitallySigned reconstructs a DigitallySigned structure from a Reader
|
|
||||||
func UnmarshalDigitallySigned(r io.Reader) (*DigitallySigned, error) {
|
|
||||||
var h byte
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &h); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read HashAlgorithm: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var s byte
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &s); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read SignatureAlgorithm: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err := readVarBytes(r, SignatureLengthBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read Signature bytes: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DigitallySigned{
|
|
||||||
HashAlgorithm: HashAlgorithm(h),
|
|
||||||
SignatureAlgorithm: SignatureAlgorithm(s),
|
|
||||||
Signature: sig,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalDigitallySignedHere(ds DigitallySigned, here []byte) ([]byte, error) {
|
|
||||||
sigLen := len(ds.Signature)
|
|
||||||
dsOutLen := 2 + SignatureLengthBytes + sigLen
|
|
||||||
if here == nil {
|
|
||||||
here = make([]byte, dsOutLen)
|
|
||||||
}
|
|
||||||
if len(here) < dsOutLen {
|
|
||||||
return nil, ErrNotEnoughBuffer
|
|
||||||
}
|
|
||||||
here = here[0:dsOutLen]
|
|
||||||
|
|
||||||
here[0] = byte(ds.HashAlgorithm)
|
|
||||||
here[1] = byte(ds.SignatureAlgorithm)
|
|
||||||
binary.BigEndian.PutUint16(here[2:4], uint16(sigLen))
|
|
||||||
copy(here[4:], ds.Signature)
|
|
||||||
|
|
||||||
return here, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalDigitallySigned marshalls a DigitallySigned structure into a byte array
|
|
||||||
func MarshalDigitallySigned(ds DigitallySigned) ([]byte, error) {
|
|
||||||
return marshalDigitallySignedHere(ds, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCertificateFormat(cert ASN1Cert) error {
|
|
||||||
if len(cert) == 0 {
|
|
||||||
return errors.New("certificate is zero length")
|
|
||||||
}
|
|
||||||
if len(cert) > MaxCertificateLength {
|
|
||||||
return errors.New("certificate too large")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkExtensionsFormat(ext CTExtensions) error {
|
|
||||||
if len(ext) > MaxExtensionsLength {
|
|
||||||
return errors.New("extensions too large")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeV1CertSCTSignatureInput(timestamp uint64, cert ASN1Cert, ext CTExtensions) ([]byte, error) {
|
|
||||||
if err := checkCertificateFormat(cert); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkExtensionsFormat(ext); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, CertificateTimestampSignatureType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, timestamp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, X509LogEntryType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := writeVarBytes(&buf, cert, CertificateLengthBytes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := writeVarBytes(&buf, ext, ExtensionsLengthBytes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeV1PrecertSCTSignatureInput(timestamp uint64, issuerKeyHash [issuerKeyHashLength]byte, tbs []byte, ext CTExtensions) ([]byte, error) {
|
|
||||||
if err := checkCertificateFormat(tbs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkExtensionsFormat(ext); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, CertificateTimestampSignatureType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, timestamp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, PrecertLogEntryType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := buf.Write(issuerKeyHash[:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := writeVarBytes(&buf, tbs, CertificateLengthBytes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := writeVarBytes(&buf, ext, ExtensionsLengthBytes); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeV1SCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) {
|
|
||||||
if sct.SCTVersion != V1 {
|
|
||||||
return nil, fmt.Errorf("unsupported SCT version, expected V1, but got %s", sct.SCTVersion)
|
|
||||||
}
|
|
||||||
if entry.Leaf.LeafType != TimestampedEntryLeafType {
|
|
||||||
return nil, fmt.Errorf("Unsupported leaf type %s", entry.Leaf.LeafType)
|
|
||||||
}
|
|
||||||
switch entry.Leaf.TimestampedEntry.EntryType {
|
|
||||||
case X509LogEntryType:
|
|
||||||
return serializeV1CertSCTSignatureInput(sct.Timestamp, entry.Leaf.TimestampedEntry.X509Entry, entry.Leaf.TimestampedEntry.Extensions)
|
|
||||||
case PrecertLogEntryType:
|
|
||||||
return serializeV1PrecertSCTSignatureInput(sct.Timestamp, entry.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash,
|
|
||||||
entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate,
|
|
||||||
entry.Leaf.TimestampedEntry.Extensions)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown TimestampedEntryLeafType %s", entry.Leaf.TimestampedEntry.EntryType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeSCTSignatureInput serializes the passed in sct and log entry into
|
|
||||||
// the correct format for signing.
|
|
||||||
func SerializeSCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) {
|
|
||||||
switch sct.SCTVersion {
|
|
||||||
case V1:
|
|
||||||
return serializeV1SCTSignatureInput(sct, entry)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializedLength will return the space (in bytes)
|
|
||||||
func (sct SignedCertificateTimestamp) SerializedLength() (int, error) {
|
|
||||||
switch sct.SCTVersion {
|
|
||||||
case V1:
|
|
||||||
extLen := len(sct.Extensions)
|
|
||||||
sigLen := len(sct.Signature.Signature)
|
|
||||||
return 1 + 32 + 8 + 2 + extLen + 2 + 2 + sigLen, nil
|
|
||||||
default:
|
|
||||||
return 0, ErrInvalidVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeV1SCTHere(sct SignedCertificateTimestamp, here []byte) ([]byte, error) {
|
|
||||||
if sct.SCTVersion != V1 {
|
|
||||||
return nil, ErrInvalidVersion
|
|
||||||
}
|
|
||||||
sctLen, err := sct.SerializedLength()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if here == nil {
|
|
||||||
here = make([]byte, sctLen)
|
|
||||||
}
|
|
||||||
if len(here) < sctLen {
|
|
||||||
return nil, ErrNotEnoughBuffer
|
|
||||||
}
|
|
||||||
if err := checkExtensionsFormat(sct.Extensions); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
here = here[0:sctLen]
|
|
||||||
|
|
||||||
// Write Version
|
|
||||||
here[0] = byte(sct.SCTVersion)
|
|
||||||
|
|
||||||
// Write LogID
|
|
||||||
copy(here[1:33], sct.LogID[:])
|
|
||||||
|
|
||||||
// Write Timestamp
|
|
||||||
binary.BigEndian.PutUint64(here[33:41], sct.Timestamp)
|
|
||||||
|
|
||||||
// Write Extensions
|
|
||||||
extLen := len(sct.Extensions)
|
|
||||||
binary.BigEndian.PutUint16(here[41:43], uint16(extLen))
|
|
||||||
n := 43 + extLen
|
|
||||||
copy(here[43:n], sct.Extensions)
|
|
||||||
|
|
||||||
// Write Signature
|
|
||||||
_, err = marshalDigitallySignedHere(sct.Signature, here[n:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return here, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeSCTHere serializes the passed in sct into the format specified
|
|
||||||
// by RFC6962 section 3.2.
|
|
||||||
// If a bytes slice here is provided then it will attempt to serialize into the
|
|
||||||
// provided byte slice, ErrNotEnoughBuffer will be returned if the buffer is
|
|
||||||
// too small.
|
|
||||||
// If a nil byte slice is provided, a buffer for will be allocated for you
|
|
||||||
// The returned slice will be sliced to the correct length.
|
|
||||||
func SerializeSCTHere(sct SignedCertificateTimestamp, here []byte) ([]byte, error) {
|
|
||||||
switch sct.SCTVersion {
|
|
||||||
case V1:
|
|
||||||
return serializeV1SCTHere(sct, here)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeSCT serializes the passed in sct into the format specified
|
|
||||||
// by RFC6962 section 3.2
|
|
||||||
// Equivalent to SerializeSCTHere(sct, nil)
|
|
||||||
func SerializeSCT(sct SignedCertificateTimestamp) ([]byte, error) {
|
|
||||||
return SerializeSCTHere(sct, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deserializeSCTV1(r io.Reader, sct *SignedCertificateTimestamp) error {
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &sct.LogID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &sct.Timestamp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ext, err := readVarBytes(r, ExtensionsLengthBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sct.Extensions = ext
|
|
||||||
ds, err := UnmarshalDigitallySigned(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sct.Signature = *ds
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeserializeSCT(r io.Reader) (*SignedCertificateTimestamp, error) {
|
|
||||||
var sct SignedCertificateTimestamp
|
|
||||||
if err := binary.Read(r, binary.BigEndian, &sct.SCTVersion); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch sct.SCTVersion {
|
|
||||||
case V1:
|
|
||||||
return &sct, deserializeSCTV1(r, &sct)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeV1STHSignatureInput(sth SignedTreeHead) ([]byte, error) {
|
|
||||||
if sth.Version != V1 {
|
|
||||||
return nil, fmt.Errorf("invalid STH version %d", sth.Version)
|
|
||||||
}
|
|
||||||
if sth.TreeSize < 0 {
|
|
||||||
return nil, fmt.Errorf("invalid tree size %d", sth.TreeSize)
|
|
||||||
}
|
|
||||||
if len(sth.SHA256RootHash) != crypto.SHA256.Size() {
|
|
||||||
return nil, fmt.Errorf("invalid TreeHash length, got %d expected %d", len(sth.SHA256RootHash), crypto.SHA256.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, TreeHashSignatureType); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, sth.Timestamp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, sth.TreeSize); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Write(&buf, binary.BigEndian, sth.SHA256RootHash); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeSTHSignatureInput serializes the passed in sth into the correct
|
|
||||||
// format for signing.
|
|
||||||
func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) {
|
|
||||||
switch sth.Version {
|
|
||||||
case V1:
|
|
||||||
return serializeV1STHSignatureInput(sth)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported STH version %d", sth.Version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
363
vendor/github.com/google/certificate-transparency/go/types.go
generated
vendored
363
vendor/github.com/google/certificate-transparency/go/types.go
generated
vendored
@@ -1,363 +0,0 @@
|
|||||||
package ct
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/google/certificate-transparency/go/x509"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
issuerKeyHashLength = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// The following structures represent those outlined in the RFC6962 document:
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// LogEntryType represents the LogEntryType enum from section 3.1 of the RFC:
|
|
||||||
// enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
|
|
||||||
type LogEntryType uint16
|
|
||||||
|
|
||||||
func (e LogEntryType) String() string {
|
|
||||||
switch e {
|
|
||||||
case X509LogEntryType:
|
|
||||||
return "X509LogEntryType"
|
|
||||||
case PrecertLogEntryType:
|
|
||||||
return "PrecertLogEntryType"
|
|
||||||
}
|
|
||||||
panic(fmt.Sprintf("No string defined for LogEntryType constant value %d", e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogEntryType constants, see section 3.1 of RFC6962.
|
|
||||||
const (
|
|
||||||
X509LogEntryType LogEntryType = 0
|
|
||||||
PrecertLogEntryType LogEntryType = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// MerkleLeafType represents the MerkleLeafType enum from section 3.4 of the
|
|
||||||
// RFC: enum { timestamped_entry(0), (255) } MerkleLeafType;
|
|
||||||
type MerkleLeafType uint8
|
|
||||||
|
|
||||||
func (m MerkleLeafType) String() string {
|
|
||||||
switch m {
|
|
||||||
case TimestampedEntryLeafType:
|
|
||||||
return "TimestampedEntryLeafType"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("UnknownLeafType(%d)", m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MerkleLeafType constants, see section 3.4 of the RFC.
|
|
||||||
const (
|
|
||||||
TimestampedEntryLeafType MerkleLeafType = 0 // Entry type for an SCT
|
|
||||||
)
|
|
||||||
|
|
||||||
// Version represents the Version enum from section 3.2 of the RFC:
|
|
||||||
// enum { v1(0), (255) } Version;
|
|
||||||
type Version uint8
|
|
||||||
|
|
||||||
func (v Version) String() string {
|
|
||||||
switch v {
|
|
||||||
case V1:
|
|
||||||
return "V1"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("UnknownVersion(%d)", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CT Version constants, see section 3.2 of the RFC.
|
|
||||||
const (
|
|
||||||
V1 Version = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// SignatureType differentiates STH signatures from SCT signatures, see RFC
|
|
||||||
// section 3.2
|
|
||||||
type SignatureType uint8
|
|
||||||
|
|
||||||
func (st SignatureType) String() string {
|
|
||||||
switch st {
|
|
||||||
case CertificateTimestampSignatureType:
|
|
||||||
return "CertificateTimestamp"
|
|
||||||
case TreeHashSignatureType:
|
|
||||||
return "TreeHash"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("UnknownSignatureType(%d)", st)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureType constants, see RFC section 3.2
|
|
||||||
const (
|
|
||||||
CertificateTimestampSignatureType SignatureType = 0
|
|
||||||
TreeHashSignatureType SignatureType = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// ASN1Cert type for holding the raw DER bytes of an ASN.1 Certificate
|
|
||||||
// (section 3.1)
|
|
||||||
type ASN1Cert []byte
|
|
||||||
|
|
||||||
// PreCert represents a Precertificate (section 3.2)
|
|
||||||
type PreCert struct {
|
|
||||||
IssuerKeyHash [issuerKeyHashLength]byte
|
|
||||||
TBSCertificate []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// CTExtensions is a representation of the raw bytes of any CtExtension
|
|
||||||
// structure (see section 3.2)
|
|
||||||
type CTExtensions []byte
|
|
||||||
|
|
||||||
// MerkleTreeNode represents an internal node in the CT tree
|
|
||||||
type MerkleTreeNode []byte
|
|
||||||
|
|
||||||
// ConsistencyProof represents a CT consistency proof (see sections 2.1.2 and
|
|
||||||
// 4.4)
|
|
||||||
type ConsistencyProof []MerkleTreeNode
|
|
||||||
|
|
||||||
// AuditPath represents a CT inclusion proof (see sections 2.1.1 and 4.5)
|
|
||||||
type AuditPath []MerkleTreeNode
|
|
||||||
|
|
||||||
// LeafInput represents a serialized MerkleTreeLeaf structure
|
|
||||||
type LeafInput []byte
|
|
||||||
|
|
||||||
// HashAlgorithm from the DigitallySigned struct
|
|
||||||
type HashAlgorithm byte
|
|
||||||
|
|
||||||
// HashAlgorithm constants
|
|
||||||
const (
|
|
||||||
None HashAlgorithm = 0
|
|
||||||
MD5 HashAlgorithm = 1
|
|
||||||
SHA1 HashAlgorithm = 2
|
|
||||||
SHA224 HashAlgorithm = 3
|
|
||||||
SHA256 HashAlgorithm = 4
|
|
||||||
SHA384 HashAlgorithm = 5
|
|
||||||
SHA512 HashAlgorithm = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
func (h HashAlgorithm) String() string {
|
|
||||||
switch h {
|
|
||||||
case None:
|
|
||||||
return "None"
|
|
||||||
case MD5:
|
|
||||||
return "MD5"
|
|
||||||
case SHA1:
|
|
||||||
return "SHA1"
|
|
||||||
case SHA224:
|
|
||||||
return "SHA224"
|
|
||||||
case SHA256:
|
|
||||||
return "SHA256"
|
|
||||||
case SHA384:
|
|
||||||
return "SHA384"
|
|
||||||
case SHA512:
|
|
||||||
return "SHA512"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("UNKNOWN(%d)", h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureAlgorithm from the the DigitallySigned struct
|
|
||||||
type SignatureAlgorithm byte
|
|
||||||
|
|
||||||
// SignatureAlgorithm constants
|
|
||||||
const (
|
|
||||||
Anonymous SignatureAlgorithm = 0
|
|
||||||
RSA SignatureAlgorithm = 1
|
|
||||||
DSA SignatureAlgorithm = 2
|
|
||||||
ECDSA SignatureAlgorithm = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s SignatureAlgorithm) String() string {
|
|
||||||
switch s {
|
|
||||||
case Anonymous:
|
|
||||||
return "Anonymous"
|
|
||||||
case RSA:
|
|
||||||
return "RSA"
|
|
||||||
case DSA:
|
|
||||||
return "DSA"
|
|
||||||
case ECDSA:
|
|
||||||
return "ECDSA"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("UNKNOWN(%d)", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DigitallySigned represents an RFC5246 DigitallySigned structure
|
|
||||||
type DigitallySigned struct {
|
|
||||||
HashAlgorithm HashAlgorithm
|
|
||||||
SignatureAlgorithm SignatureAlgorithm
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBase64String populates the DigitallySigned structure from the base64 data passed in.
|
|
||||||
// Returns an error if the base64 data is invalid.
|
|
||||||
func (d *DigitallySigned) FromBase64String(b64 string) error {
|
|
||||||
raw, err := base64.StdEncoding.DecodeString(b64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err)
|
|
||||||
}
|
|
||||||
ds, err := UnmarshalDigitallySigned(bytes.NewReader(raw))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
|
||||||
}
|
|
||||||
*d = *ds
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base64String returns the base64 representation of the DigitallySigned struct.
|
|
||||||
func (d DigitallySigned) Base64String() (string, error) {
|
|
||||||
b, err := MarshalDigitallySigned(d)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return base64.StdEncoding.EncodeToString(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaller interface.
|
|
||||||
func (d DigitallySigned) MarshalJSON() ([]byte, error) {
|
|
||||||
b64, err := d.Base64String()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
return []byte(`"` + b64 + `"`), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|
||||||
func (d *DigitallySigned) UnmarshalJSON(b []byte) error {
|
|
||||||
var content string
|
|
||||||
if err := json.Unmarshal(b, &content); err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
|
|
||||||
}
|
|
||||||
return d.FromBase64String(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogEntry represents the contents of an entry in a CT log, see section 3.1.
|
|
||||||
type LogEntry struct {
|
|
||||||
Index int64
|
|
||||||
Leaf MerkleTreeLeaf
|
|
||||||
X509Cert *x509.Certificate
|
|
||||||
Precert *Precertificate
|
|
||||||
Chain []ASN1Cert
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHA256Hash represents the output from the SHA256 hash function.
|
|
||||||
type SHA256Hash [sha256.Size]byte
|
|
||||||
|
|
||||||
// FromBase64String populates the SHA256 struct with the contents of the base64 data passed in.
|
|
||||||
func (s *SHA256Hash) FromBase64String(b64 string) error {
|
|
||||||
bs, err := base64.StdEncoding.DecodeString(b64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to unbase64 LogID: %v", err)
|
|
||||||
}
|
|
||||||
if len(bs) != sha256.Size {
|
|
||||||
return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs))
|
|
||||||
}
|
|
||||||
copy(s[:], bs)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base64String returns the base64 representation of this SHA256Hash.
|
|
||||||
func (s SHA256Hash) Base64String() string {
|
|
||||||
return base64.StdEncoding.EncodeToString(s[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaller interface for SHA256Hash.
|
|
||||||
func (s SHA256Hash) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(`"` + s.Base64String() + `"`), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
|
||||||
func (s *SHA256Hash) UnmarshalJSON(b []byte) error {
|
|
||||||
var content string
|
|
||||||
if err := json.Unmarshal(b, &content); err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err)
|
|
||||||
}
|
|
||||||
return s.FromBase64String(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignedTreeHead represents the structure returned by the get-sth CT method
|
|
||||||
// after base64 decoding. See sections 3.5 and 4.3 in the RFC)
|
|
||||||
type SignedTreeHead struct {
|
|
||||||
Version Version `json:"sth_version"` // The version of the protocol to which the STH conforms
|
|
||||||
TreeSize uint64 `json:"tree_size"` // The number of entries in the new tree
|
|
||||||
Timestamp uint64 `json:"timestamp"` // The time at which the STH was created
|
|
||||||
SHA256RootHash SHA256Hash `json:"sha256_root_hash"` // The root hash of the log's Merkle tree
|
|
||||||
TreeHeadSignature DigitallySigned `json:"tree_head_signature"` // The Log's signature for this STH (see RFC section 3.5)
|
|
||||||
LogID SHA256Hash `json:"log_id"` // The SHA256 hash of the log's public key
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignedCertificateTimestamp represents the structure returned by the
|
|
||||||
// add-chain and add-pre-chain methods after base64 decoding. (see RFC sections
|
|
||||||
// 3.2 ,4.1 and 4.2)
|
|
||||||
type SignedCertificateTimestamp struct {
|
|
||||||
SCTVersion Version // The version of the protocol to which the SCT conforms
|
|
||||||
LogID SHA256Hash // the SHA-256 hash of the log's public key, calculated over
|
|
||||||
// the DER encoding of the key represented as SubjectPublicKeyInfo.
|
|
||||||
Timestamp uint64 // Timestamp (in ms since unix epoc) at which the SCT was issued
|
|
||||||
Extensions CTExtensions // For future extensions to the protocol
|
|
||||||
Signature DigitallySigned // The Log's signature for this SCT
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s SignedCertificateTimestamp) String() string {
|
|
||||||
return fmt.Sprintf("{Version:%d LogId:%s Timestamp:%d Extensions:'%s' Signature:%v}", s.SCTVersion,
|
|
||||||
base64.StdEncoding.EncodeToString(s.LogID[:]),
|
|
||||||
s.Timestamp,
|
|
||||||
s.Extensions,
|
|
||||||
s.Signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampedEntry is part of the MerkleTreeLeaf structure.
|
|
||||||
// See RFC section 3.4
|
|
||||||
type TimestampedEntry struct {
|
|
||||||
Timestamp uint64
|
|
||||||
EntryType LogEntryType
|
|
||||||
X509Entry ASN1Cert
|
|
||||||
PrecertEntry PreCert
|
|
||||||
Extensions CTExtensions
|
|
||||||
}
|
|
||||||
|
|
||||||
// MerkleTreeLeaf represents the deserialized sructure of the hash input for the
|
|
||||||
// leaves of a log's Merkle tree. See RFC section 3.4
|
|
||||||
type MerkleTreeLeaf struct {
|
|
||||||
Version Version // the version of the protocol to which the MerkleTreeLeaf corresponds
|
|
||||||
LeafType MerkleLeafType // The type of the leaf input, currently only TimestampedEntry can exist
|
|
||||||
TimestampedEntry TimestampedEntry // The entry data itself
|
|
||||||
}
|
|
||||||
|
|
||||||
// Precertificate represents the parsed CT Precertificate structure.
|
|
||||||
type Precertificate struct {
|
|
||||||
// Raw DER bytes of the precert
|
|
||||||
Raw []byte
|
|
||||||
// SHA256 hash of the issuing key
|
|
||||||
IssuerKeyHash [issuerKeyHashLength]byte
|
|
||||||
// Parsed TBSCertificate structure (held in an x509.Certificate for ease of
|
|
||||||
// access.
|
|
||||||
TBSCertificate x509.Certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
// X509Certificate returns the X.509 Certificate contained within the
|
|
||||||
// MerkleTreeLeaf.
|
|
||||||
// Returns a pointer to an x509.Certificate or a non-nil error.
|
|
||||||
func (m *MerkleTreeLeaf) X509Certificate() (*x509.Certificate, error) {
|
|
||||||
return x509.ParseCertificate(m.TimestampedEntry.X509Entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
type sctError int
|
|
||||||
|
|
||||||
// Preallocate errors for performance
|
|
||||||
var (
|
|
||||||
ErrInvalidVersion error = sctError(1)
|
|
||||||
ErrNotEnoughBuffer error = sctError(2)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e sctError) Error() string {
|
|
||||||
switch e {
|
|
||||||
case ErrInvalidVersion:
|
|
||||||
return "invalid SCT version detected"
|
|
||||||
case ErrNotEnoughBuffer:
|
|
||||||
return "provided buffer was too small"
|
|
||||||
default:
|
|
||||||
return "unknown error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
78
vendor/github.com/google/certificate-transparency/go/x509/BUILD
generated
vendored
78
vendor/github.com/google/certificate-transparency/go/x509/BUILD
generated
vendored
@@ -1,78 +0,0 @@
|
|||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"cert_pool.go",
|
|
||||||
"pem_decrypt.go",
|
|
||||||
"pkcs1.go",
|
|
||||||
"pkcs8.go",
|
|
||||||
"root.go",
|
|
||||||
"sec1.go",
|
|
||||||
"verify.go",
|
|
||||||
"x509.go",
|
|
||||||
] + select({
|
|
||||||
"@io_bazel_rules_go//go/platform:darwin": [
|
|
||||||
"root_darwin.go",
|
|
||||||
"root_stub.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
|
||||||
"root_unix.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
|
||||||
"root_unix.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:linux": [
|
|
||||||
"root_unix.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
|
||||||
"root_unix.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
|
||||||
"root_unix.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:plan9": [
|
|
||||||
"root_plan9.go",
|
|
||||||
],
|
|
||||||
"@io_bazel_rules_go//go/platform:windows": [
|
|
||||||
"root_windows.go",
|
|
||||||
],
|
|
||||||
"//conditions:default": [],
|
|
||||||
}),
|
|
||||||
cgo = True,
|
|
||||||
clinkopts = select({
|
|
||||||
"@io_bazel_rules_go//go/platform:darwin": [
|
|
||||||
"-framework CoreFoundation -framework Security",
|
|
||||||
],
|
|
||||||
"//conditions:default": [],
|
|
||||||
}),
|
|
||||||
copts = select({
|
|
||||||
"@io_bazel_rules_go//go/platform:darwin": [
|
|
||||||
"-mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060",
|
|
||||||
],
|
|
||||||
"//conditions:default": [],
|
|
||||||
}),
|
|
||||||
importpath = "github.com/google/certificate-transparency/go/x509",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = [
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/asn1:go_default_library",
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/x509/pkix:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [
|
|
||||||
":package-srcs",
|
|
||||||
"//vendor/github.com/google/certificate-transparency/go/x509/pkix:all-srcs",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
56
vendor/github.com/google/certificate-transparency/go/x509/pkcs8.go
generated
vendored
56
vendor/github.com/google/certificate-transparency/go/x509/pkcs8.go
generated
vendored
@@ -1,56 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package x509
|
|
||||||
|
|
||||||
import (
|
|
||||||
// START CT CHANGES
|
|
||||||
"github.com/google/certificate-transparency/go/asn1"
|
|
||||||
"github.com/google/certificate-transparency/go/x509/pkix"
|
|
||||||
// END CT CHANGES
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
|
|
||||||
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
|
|
||||||
// and RFC5208.
|
|
||||||
type pkcs8 struct {
|
|
||||||
Version int
|
|
||||||
Algo pkix.AlgorithmIdentifier
|
|
||||||
PrivateKey []byte
|
|
||||||
// optional attributes omitted.
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
|
|
||||||
// http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208.
|
|
||||||
func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
|
|
||||||
var privKey pkcs8
|
|
||||||
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):
|
|
||||||
key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
|
|
||||||
case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
|
|
||||||
bytes := privKey.Algo.Parameters.FullBytes
|
|
||||||
namedCurveOID := new(asn1.ObjectIdentifier)
|
|
||||||
if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
|
|
||||||
namedCurveOID = nil
|
|
||||||
}
|
|
||||||
key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
|
|
||||||
}
|
|
||||||
return key, nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
173
vendor/github.com/google/certificate-transparency/go/x509/pkix/pkix.go
generated
vendored
173
vendor/github.com/google/certificate-transparency/go/x509/pkix/pkix.go
generated
vendored
@@ -1,173 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package pkix contains shared, low level structures used for ASN.1 parsing
|
|
||||||
// and serialization of X.509 certificates, CRL and OCSP.
|
|
||||||
package pkix
|
|
||||||
|
|
||||||
import (
|
|
||||||
// START CT CHANGES
|
|
||||||
"github.com/google/certificate-transparency/go/asn1"
|
|
||||||
// END CT CHANGES
|
|
||||||
"math/big"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
|
||||||
// 5280, section 4.1.1.2.
|
|
||||||
type AlgorithmIdentifier struct {
|
|
||||||
Algorithm asn1.ObjectIdentifier
|
|
||||||
Parameters asn1.RawValue `asn1:"optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RDNSequence []RelativeDistinguishedNameSET
|
|
||||||
|
|
||||||
type RelativeDistinguishedNameSET []AttributeTypeAndValue
|
|
||||||
|
|
||||||
// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
|
|
||||||
// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
|
|
||||||
type AttributeTypeAndValue struct {
|
|
||||||
Type asn1.ObjectIdentifier
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extension represents the ASN.1 structure of the same name. See RFC
|
|
||||||
// 5280, section 4.2.
|
|
||||||
type Extension struct {
|
|
||||||
Id asn1.ObjectIdentifier
|
|
||||||
Critical bool `asn1:"optional"`
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name represents an X.509 distinguished name. This only includes the common
|
|
||||||
// elements of a DN. Additional elements in the name are ignored.
|
|
||||||
type Name struct {
|
|
||||||
Country, Organization, OrganizationalUnit []string
|
|
||||||
Locality, Province []string
|
|
||||||
StreetAddress, PostalCode []string
|
|
||||||
SerialNumber, CommonName string
|
|
||||||
|
|
||||||
Names []AttributeTypeAndValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
|
|
||||||
for _, rdn := range *rdns {
|
|
||||||
if len(rdn) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
atv := rdn[0]
|
|
||||||
n.Names = append(n.Names, atv)
|
|
||||||
value, ok := atv.Value.(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
t := atv.Type
|
|
||||||
if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
|
|
||||||
switch t[3] {
|
|
||||||
case 3:
|
|
||||||
n.CommonName = value
|
|
||||||
case 5:
|
|
||||||
n.SerialNumber = value
|
|
||||||
case 6:
|
|
||||||
n.Country = append(n.Country, value)
|
|
||||||
case 7:
|
|
||||||
n.Locality = append(n.Locality, value)
|
|
||||||
case 8:
|
|
||||||
n.Province = append(n.Province, value)
|
|
||||||
case 9:
|
|
||||||
n.StreetAddress = append(n.StreetAddress, value)
|
|
||||||
case 10:
|
|
||||||
n.Organization = append(n.Organization, value)
|
|
||||||
case 11:
|
|
||||||
n.OrganizationalUnit = append(n.OrganizationalUnit, value)
|
|
||||||
case 17:
|
|
||||||
n.PostalCode = append(n.PostalCode, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
oidCountry = []int{2, 5, 4, 6}
|
|
||||||
oidOrganization = []int{2, 5, 4, 10}
|
|
||||||
oidOrganizationalUnit = []int{2, 5, 4, 11}
|
|
||||||
oidCommonName = []int{2, 5, 4, 3}
|
|
||||||
oidSerialNumber = []int{2, 5, 4, 5}
|
|
||||||
oidLocality = []int{2, 5, 4, 7}
|
|
||||||
oidProvince = []int{2, 5, 4, 8}
|
|
||||||
oidStreetAddress = []int{2, 5, 4, 9}
|
|
||||||
oidPostalCode = []int{2, 5, 4, 17}
|
|
||||||
)
|
|
||||||
|
|
||||||
// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
|
|
||||||
// and returns the new value. The relativeDistinguishedNameSET contains an
|
|
||||||
// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
|
|
||||||
// search for AttributeTypeAndValue.
|
|
||||||
func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
|
|
||||||
if len(values) == 0 {
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
|
|
||||||
s := make([]AttributeTypeAndValue, len(values))
|
|
||||||
for i, value := range values {
|
|
||||||
s[i].Type = oid
|
|
||||||
s[i].Value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(in, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n Name) ToRDNSequence() (ret RDNSequence) {
|
|
||||||
ret = appendRDNs(ret, n.Country, oidCountry)
|
|
||||||
ret = appendRDNs(ret, n.Organization, oidOrganization)
|
|
||||||
ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
|
|
||||||
ret = appendRDNs(ret, n.Locality, oidLocality)
|
|
||||||
ret = appendRDNs(ret, n.Province, oidProvince)
|
|
||||||
ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
|
|
||||||
ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
|
|
||||||
if len(n.CommonName) > 0 {
|
|
||||||
ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
|
|
||||||
}
|
|
||||||
if len(n.SerialNumber) > 0 {
|
|
||||||
ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// CertificateList represents the ASN.1 structure of the same name. See RFC
|
|
||||||
// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
|
|
||||||
// signature.
|
|
||||||
type CertificateList struct {
|
|
||||||
TBSCertList TBSCertificateList
|
|
||||||
SignatureAlgorithm AlgorithmIdentifier
|
|
||||||
SignatureValue asn1.BitString
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasExpired reports whether now is past the expiry time of certList.
|
|
||||||
func (certList *CertificateList) HasExpired(now time.Time) bool {
|
|
||||||
return now.After(certList.TBSCertList.NextUpdate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
|
|
||||||
// 5280, section 5.1.
|
|
||||||
type TBSCertificateList struct {
|
|
||||||
Raw asn1.RawContent
|
|
||||||
Version int `asn1:"optional,default:2"`
|
|
||||||
Signature AlgorithmIdentifier
|
|
||||||
Issuer RDNSequence
|
|
||||||
ThisUpdate time.Time
|
|
||||||
NextUpdate time.Time
|
|
||||||
RevokedCertificates []RevokedCertificate `asn1:"optional"`
|
|
||||||
Extensions []Extension `asn1:"tag:0,optional,explicit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
|
|
||||||
// 5280, section 5.1.
|
|
||||||
type RevokedCertificate struct {
|
|
||||||
SerialNumber *big.Int
|
|
||||||
RevocationTime time.Time
|
|
||||||
Extensions []Extension `asn1:"optional"`
|
|
||||||
}
|
|
||||||
83
vendor/github.com/google/certificate-transparency/go/x509/root_darwin.go
generated
vendored
83
vendor/github.com/google/certificate-transparency/go/x509/root_darwin.go
generated
vendored
@@ -1,83 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build darwin,cgo
|
|
||||||
|
|
||||||
package x509
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
|
|
||||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <Security/Security.h>
|
|
||||||
|
|
||||||
// FetchPEMRootsCTX509 fetches the system's list of trusted X.509 root certificates.
|
|
||||||
//
|
|
||||||
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
|
|
||||||
// certificates of the system. On failure, the function returns -1.
|
|
||||||
//
|
|
||||||
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
|
|
||||||
// we've consumed its content.
|
|
||||||
int FetchPEMRootsCTX509(CFDataRef *pemRoots) {
|
|
||||||
if (pemRoots == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFArrayRef certs = NULL;
|
|
||||||
OSStatus err = SecTrustCopyAnchorCertificates(&certs);
|
|
||||||
if (err != noErr) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
|
||||||
int i, ncerts = CFArrayGetCount(certs);
|
|
||||||
for (i = 0; i < ncerts; i++) {
|
|
||||||
CFDataRef data = NULL;
|
|
||||||
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
|
|
||||||
if (cert == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
|
|
||||||
// Once we support weak imports via cgo we should prefer that, and fall back to this
|
|
||||||
// for older systems.
|
|
||||||
err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
|
|
||||||
if (err != noErr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != NULL) {
|
|
||||||
CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
|
|
||||||
CFRelease(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(certs);
|
|
||||||
|
|
||||||
*pemRoots = combinedData;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initSystemRoots() {
|
|
||||||
roots := NewCertPool()
|
|
||||||
|
|
||||||
var data C.CFDataRef = nil
|
|
||||||
err := C.FetchPEMRootsCTX509(&data)
|
|
||||||
if err == -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer C.CFRelease(C.CFTypeRef(data))
|
|
||||||
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
|
|
||||||
roots.AppendCertsFromPEM(buf)
|
|
||||||
systemRoots = roots
|
|
||||||
}
|
|
||||||
14
vendor/github.com/google/certificate-transparency/go/x509/root_stub.go
generated
vendored
14
vendor/github.com/google/certificate-transparency/go/x509/root_stub.go
generated
vendored
@@ -1,14 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build darwin,!cgo
|
|
||||||
|
|
||||||
package x509
|
|
||||||
|
|
||||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initSystemRoots() {
|
|
||||||
}
|
|
||||||
37
vendor/github.com/google/certificate-transparency/go/x509/root_unix.go
generated
vendored
37
vendor/github.com/google/certificate-transparency/go/x509/root_unix.go
generated
vendored
@@ -1,37 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build dragonfly freebsd linux openbsd netbsd
|
|
||||||
|
|
||||||
package x509
|
|
||||||
|
|
||||||
import "io/ioutil"
|
|
||||||
|
|
||||||
// Possible certificate files; stop after finding one.
|
|
||||||
var certFiles = []string{
|
|
||||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
|
||||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
|
|
||||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
|
||||||
"/etc/ssl/cert.pem", // OpenBSD
|
|
||||||
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initSystemRoots() {
|
|
||||||
roots := NewCertPool()
|
|
||||||
for _, file := range certFiles {
|
|
||||||
data, err := ioutil.ReadFile(file)
|
|
||||||
if err == nil {
|
|
||||||
roots.AppendCertsFromPEM(data)
|
|
||||||
systemRoots = roots
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the files failed to load. systemRoots will be nil which will
|
|
||||||
// trigger a specific error at verification time.
|
|
||||||
}
|
|
||||||
476
vendor/github.com/google/certificate-transparency/go/x509/verify.go
generated
vendored
476
vendor/github.com/google/certificate-transparency/go/x509/verify.go
generated
vendored
@@ -1,476 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package x509
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InvalidReason int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// NotAuthorizedToSign results when a certificate is signed by another
|
|
||||||
// which isn't marked as a CA certificate.
|
|
||||||
NotAuthorizedToSign InvalidReason = iota
|
|
||||||
// Expired results when a certificate has expired, based on the time
|
|
||||||
// given in the VerifyOptions.
|
|
||||||
Expired
|
|
||||||
// CANotAuthorizedForThisName results when an intermediate or root
|
|
||||||
// certificate has a name constraint which doesn't include the name
|
|
||||||
// being checked.
|
|
||||||
CANotAuthorizedForThisName
|
|
||||||
// TooManyIntermediates results when a path length constraint is
|
|
||||||
// violated.
|
|
||||||
TooManyIntermediates
|
|
||||||
// IncompatibleUsage results when the certificate's key usage indicates
|
|
||||||
// that it may only be used for a different purpose.
|
|
||||||
IncompatibleUsage
|
|
||||||
)
|
|
||||||
|
|
||||||
// CertificateInvalidError results when an odd error occurs. Users of this
|
|
||||||
// library probably want to handle all these errors uniformly.
|
|
||||||
type CertificateInvalidError struct {
|
|
||||||
Cert *Certificate
|
|
||||||
Reason InvalidReason
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e CertificateInvalidError) Error() string {
|
|
||||||
switch e.Reason {
|
|
||||||
case NotAuthorizedToSign:
|
|
||||||
return "x509: certificate is not authorized to sign other certificates"
|
|
||||||
case Expired:
|
|
||||||
return "x509: certificate has expired or is not yet valid"
|
|
||||||
case CANotAuthorizedForThisName:
|
|
||||||
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
|
|
||||||
case TooManyIntermediates:
|
|
||||||
return "x509: too many intermediates for path length constraint"
|
|
||||||
case IncompatibleUsage:
|
|
||||||
return "x509: certificate specifies an incompatible key usage"
|
|
||||||
}
|
|
||||||
return "x509: unknown error"
|
|
||||||
}
|
|
||||||
|
|
||||||
// HostnameError results when the set of authorized names doesn't match the
|
|
||||||
// requested name.
|
|
||||||
type HostnameError struct {
|
|
||||||
Certificate *Certificate
|
|
||||||
Host string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HostnameError) Error() string {
|
|
||||||
c := h.Certificate
|
|
||||||
|
|
||||||
var valid string
|
|
||||||
if ip := net.ParseIP(h.Host); ip != nil {
|
|
||||||
// Trying to validate an IP
|
|
||||||
if len(c.IPAddresses) == 0 {
|
|
||||||
return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
|
|
||||||
}
|
|
||||||
for _, san := range c.IPAddresses {
|
|
||||||
if len(valid) > 0 {
|
|
||||||
valid += ", "
|
|
||||||
}
|
|
||||||
valid += san.String()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if len(c.DNSNames) > 0 {
|
|
||||||
valid = strings.Join(c.DNSNames, ", ")
|
|
||||||
} else {
|
|
||||||
valid = c.Subject.CommonName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "x509: certificate is valid for " + valid + ", not " + h.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnknownAuthorityError results when the certificate issuer is unknown
|
|
||||||
type UnknownAuthorityError struct {
|
|
||||||
cert *Certificate
|
|
||||||
// hintErr contains an error that may be helpful in determining why an
|
|
||||||
// authority wasn't found.
|
|
||||||
hintErr error
|
|
||||||
// hintCert contains a possible authority certificate that was rejected
|
|
||||||
// because of the error in hintErr.
|
|
||||||
hintCert *Certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e UnknownAuthorityError) Error() string {
|
|
||||||
s := "x509: certificate signed by unknown authority"
|
|
||||||
if e.hintErr != nil {
|
|
||||||
certName := e.hintCert.Subject.CommonName
|
|
||||||
if len(certName) == 0 {
|
|
||||||
if len(e.hintCert.Subject.Organization) > 0 {
|
|
||||||
certName = e.hintCert.Subject.Organization[0]
|
|
||||||
}
|
|
||||||
certName = "serial:" + e.hintCert.SerialNumber.String()
|
|
||||||
}
|
|
||||||
s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemRootsError results when we fail to load the system root certificates.
|
|
||||||
type SystemRootsError struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e SystemRootsError) Error() string {
|
|
||||||
return "x509: failed to load system roots and no roots provided"
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
|
|
||||||
// because other PKIX verification APIs have ended up needing many options.
|
|
||||||
type VerifyOptions struct {
|
|
||||||
DNSName string
|
|
||||||
Intermediates *CertPool
|
|
||||||
Roots *CertPool // if nil, the system roots are used
|
|
||||||
CurrentTime time.Time // if zero, the current time is used
|
|
||||||
DisableTimeChecks bool
|
|
||||||
// KeyUsage specifies which Extended Key Usage values are acceptable.
|
|
||||||
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
|
|
||||||
// constraint down the chain which mirrors Windows CryptoAPI behaviour,
|
|
||||||
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
|
|
||||||
KeyUsages []ExtKeyUsage
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
leafCertificate = iota
|
|
||||||
intermediateCertificate
|
|
||||||
rootCertificate
|
|
||||||
)
|
|
||||||
|
|
||||||
// isValid performs validity checks on the c.
|
|
||||||
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
|
||||||
if !opts.DisableTimeChecks {
|
|
||||||
now := opts.CurrentTime
|
|
||||||
if now.IsZero() {
|
|
||||||
now = time.Now()
|
|
||||||
}
|
|
||||||
if now.Before(c.NotBefore) || now.After(c.NotAfter) {
|
|
||||||
return CertificateInvalidError{c, Expired}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.PermittedDNSDomains) > 0 {
|
|
||||||
ok := false
|
|
||||||
for _, domain := range c.PermittedDNSDomains {
|
|
||||||
if opts.DNSName == domain ||
|
|
||||||
(strings.HasSuffix(opts.DNSName, domain) &&
|
|
||||||
len(opts.DNSName) >= 1+len(domain) &&
|
|
||||||
opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
|
|
||||||
ok = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return CertificateInvalidError{c, CANotAuthorizedForThisName}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyUsage status flags are ignored. From Engineering Security, Peter
|
|
||||||
// Gutmann: A European government CA marked its signing certificates as
|
|
||||||
// being valid for encryption only, but no-one noticed. Another
|
|
||||||
// European CA marked its signature keys as not being valid for
|
|
||||||
// signatures. A different CA marked its own trusted root certificate
|
|
||||||
// as being invalid for certificate signing. Another national CA
|
|
||||||
// distributed a certificate to be used to encrypt data for the
|
|
||||||
// country’s tax authority that was marked as only being usable for
|
|
||||||
// digital signatures but not for encryption. Yet another CA reversed
|
|
||||||
// the order of the bit flags in the keyUsage due to confusion over
|
|
||||||
// encoding endianness, essentially setting a random keyUsage in
|
|
||||||
// certificates that it issued. Another CA created a self-invalidating
|
|
||||||
// certificate by adding a certificate policy statement stipulating
|
|
||||||
// that the certificate had to be used strictly as specified in the
|
|
||||||
// keyUsage, and a keyUsage containing a flag indicating that the RSA
|
|
||||||
// encryption key could only be used for Diffie-Hellman key agreement.
|
|
||||||
|
|
||||||
if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
|
|
||||||
return CertificateInvalidError{c, NotAuthorizedToSign}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
|
|
||||||
numIntermediates := len(currentChain) - 1
|
|
||||||
if numIntermediates > c.MaxPathLen {
|
|
||||||
return CertificateInvalidError{c, TooManyIntermediates}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify attempts to verify c by building one or more chains from c to a
|
|
||||||
// certificate in opts.Roots, using certificates in opts.Intermediates if
|
|
||||||
// needed. If successful, it returns one or more chains where the first
|
|
||||||
// element of the chain is c and the last element is from opts.Roots.
|
|
||||||
//
|
|
||||||
// WARNING: this doesn't do any revocation checking.
|
|
||||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
|
||||||
// Use Windows's own verification and chain building.
|
|
||||||
if opts.Roots == nil && runtime.GOOS == "windows" {
|
|
||||||
return c.systemVerify(&opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Roots == nil {
|
|
||||||
opts.Roots = systemRootsPool()
|
|
||||||
if opts.Roots == nil {
|
|
||||||
return nil, SystemRootsError{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.isValid(leafCertificate, nil, &opts)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(opts.DNSName) > 0 {
|
|
||||||
err = c.VerifyHostname(opts.DNSName)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
keyUsages := opts.KeyUsages
|
|
||||||
if len(keyUsages) == 0 {
|
|
||||||
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If any key usage is acceptable then we're done.
|
|
||||||
for _, usage := range keyUsages {
|
|
||||||
if usage == ExtKeyUsageAny {
|
|
||||||
chains = candidateChains
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, candidate := range candidateChains {
|
|
||||||
if checkChainForKeyUsage(candidate, keyUsages) {
|
|
||||||
chains = append(chains, candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(chains) == 0 {
|
|
||||||
err = CertificateInvalidError{c, IncompatibleUsage}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
|
|
||||||
n := make([]*Certificate, len(chain)+1)
|
|
||||||
copy(n, chain)
|
|
||||||
n[len(chain)] = cert
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
|
||||||
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
|
|
||||||
for _, rootNum := range possibleRoots {
|
|
||||||
root := opts.Roots.certs[rootNum]
|
|
||||||
err = root.isValid(rootCertificate, currentChain, opts)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chains = append(chains, appendToFreshChain(currentChain, root))
|
|
||||||
}
|
|
||||||
|
|
||||||
possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
|
|
||||||
nextIntermediate:
|
|
||||||
for _, intermediateNum := range possibleIntermediates {
|
|
||||||
intermediate := opts.Intermediates.certs[intermediateNum]
|
|
||||||
for _, cert := range currentChain {
|
|
||||||
if cert == intermediate {
|
|
||||||
continue nextIntermediate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var childChains [][]*Certificate
|
|
||||||
childChains, ok := cache[intermediateNum]
|
|
||||||
if !ok {
|
|
||||||
childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
|
|
||||||
cache[intermediateNum] = childChains
|
|
||||||
}
|
|
||||||
chains = append(chains, childChains...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(chains) > 0 {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(chains) == 0 && err == nil {
|
|
||||||
hintErr := rootErr
|
|
||||||
hintCert := failedRoot
|
|
||||||
if hintErr == nil {
|
|
||||||
hintErr = intermediateErr
|
|
||||||
hintCert = failedIntermediate
|
|
||||||
}
|
|
||||||
err = UnknownAuthorityError{c, hintErr, hintCert}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchHostnames(pattern, host string) bool {
|
|
||||||
if len(pattern) == 0 || len(host) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
patternParts := strings.Split(pattern, ".")
|
|
||||||
hostParts := strings.Split(host, ".")
|
|
||||||
|
|
||||||
if len(patternParts) != len(hostParts) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, patternPart := range patternParts {
|
|
||||||
if patternPart == "*" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if patternPart != hostParts[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
|
|
||||||
// an explicitly ASCII function to avoid any sharp corners resulting from
|
|
||||||
// performing Unicode operations on DNS labels.
|
|
||||||
func toLowerCaseASCII(in string) string {
|
|
||||||
// If the string is already lower-case then there's nothing to do.
|
|
||||||
isAlreadyLowerCase := true
|
|
||||||
for _, c := range in {
|
|
||||||
if c == utf8.RuneError {
|
|
||||||
// If we get a UTF-8 error then there might be
|
|
||||||
// upper-case ASCII bytes in the invalid sequence.
|
|
||||||
isAlreadyLowerCase = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if 'A' <= c && c <= 'Z' {
|
|
||||||
isAlreadyLowerCase = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isAlreadyLowerCase {
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
|
|
||||||
out := []byte(in)
|
|
||||||
for i, c := range out {
|
|
||||||
if 'A' <= c && c <= 'Z' {
|
|
||||||
out[i] += 'a' - 'A'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyHostname returns nil if c is a valid certificate for the named host.
|
|
||||||
// Otherwise it returns an error describing the mismatch.
|
|
||||||
func (c *Certificate) VerifyHostname(h string) error {
|
|
||||||
// IP addresses may be written in [ ].
|
|
||||||
candidateIP := h
|
|
||||||
if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
|
|
||||||
candidateIP = h[1 : len(h)-1]
|
|
||||||
}
|
|
||||||
if ip := net.ParseIP(candidateIP); ip != nil {
|
|
||||||
// We only match IP addresses against IP SANs.
|
|
||||||
// https://tools.ietf.org/html/rfc6125#appendix-B.2
|
|
||||||
for _, candidate := range c.IPAddresses {
|
|
||||||
if ip.Equal(candidate) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return HostnameError{c, candidateIP}
|
|
||||||
}
|
|
||||||
|
|
||||||
lowered := toLowerCaseASCII(h)
|
|
||||||
|
|
||||||
if len(c.DNSNames) > 0 {
|
|
||||||
for _, match := range c.DNSNames {
|
|
||||||
if matchHostnames(toLowerCaseASCII(match), lowered) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If Subject Alt Name is given, we ignore the common name.
|
|
||||||
} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return HostnameError{c, h}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
|
|
||||||
usages := make([]ExtKeyUsage, len(keyUsages))
|
|
||||||
copy(usages, keyUsages)
|
|
||||||
|
|
||||||
if len(chain) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
usagesRemaining := len(usages)
|
|
||||||
|
|
||||||
// We walk down the list and cross out any usages that aren't supported
|
|
||||||
// by each certificate. If we cross out all the usages, then the chain
|
|
||||||
// is unacceptable.
|
|
||||||
|
|
||||||
for i := len(chain) - 1; i >= 0; i-- {
|
|
||||||
cert := chain[i]
|
|
||||||
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
|
|
||||||
// The certificate doesn't have any extended key usage specified.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, usage := range cert.ExtKeyUsage {
|
|
||||||
if usage == ExtKeyUsageAny {
|
|
||||||
// The certificate is explicitly good for any usage.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidUsage ExtKeyUsage = -1
|
|
||||||
|
|
||||||
NextRequestedUsage:
|
|
||||||
for i, requestedUsage := range usages {
|
|
||||||
if requestedUsage == invalidUsage {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, usage := range cert.ExtKeyUsage {
|
|
||||||
if requestedUsage == usage {
|
|
||||||
continue NextRequestedUsage
|
|
||||||
} else if requestedUsage == ExtKeyUsageServerAuth &&
|
|
||||||
(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
|
|
||||||
usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
|
|
||||||
// In order to support COMODO
|
|
||||||
// certificate chains, we have to
|
|
||||||
// accept Netscape or Microsoft SGC
|
|
||||||
// usages as equal to ServerAuth.
|
|
||||||
continue NextRequestedUsage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
usages[i] = invalidUsage
|
|
||||||
usagesRemaining--
|
|
||||||
if usagesRemaining == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
1622
vendor/github.com/google/certificate-transparency/go/x509/x509.go
generated
vendored
1622
vendor/github.com/google/certificate-transparency/go/x509/x509.go
generated
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user