{"action":"created","comment":{"url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/comments/197272564","pull_request_review_id":130937193,"id":197272564,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NzI3MjU2NA==","diff_hunk":"@@ -0,0 +1,508 @@\n+// Copyright 2018 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n+package tls\n+\n+// Delegated credentials for TLS\n+// (https://tools.ietf.org/html/draft-ietf-tls-subcerts) is an IETF Internet\n+// draft and proposed TLS extension. If the client supports this extension, then\n+// the server may use a \"delegated credential\" as the signing key in the\n+// handshake. A delegated credential is a short lived public/secret key pair\n+// delegated to the server by an entity trusted by the client. This allows a\n+// middlebox to terminate a TLS connection on behalf of the entity; for example,\n+// this can be used to delegate TLS termination to a reverse proxy. Credentials\n+// can't be revoked; in order to mitigate risk in case the middlebox is\n+// compromised, the credential is only valid for a short time (days, hours, or\n+// even minutes).\n+//\n+// BUG(cjpatton) Subcerts: Need to add support for PKCS1, PSS, and EdDSA.\n+// Currently delegated credentials only support ECDSA. The delegator must also\n+// use an ECDSA key.\n+\n+import (\n+\t\"bytes\"\n+\t\"crypto\"\n+\t\"crypto/ecdsa\"\n+\t\"crypto/elliptic\"\n+\t\"crypto/rand\"\n+\t\"crypto/x509\"\n+\t\"crypto/x509/pkix\"\n+\t\"encoding/asn1\"\n+\t\"encoding/binary\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"time\"\n+)\n+\n+const (\n+\tdcMaxTTLSeconds   = 60 * 60 * 24 * 7 // 7 days\n+\tdcMaxTTL          = time.Duration(dcMaxTTLSeconds * time.Second)\n+\tdcMaxPublicKeyLen = 1 << 16 // Bytes\n+\tdcMaxSignatureLen = 1 << 16 // Bytes\n+)\n+\n+var errNoDelegationUsage = errors.New(\"certificate not authorized for delegation\")\n+\n+// delegationUsageId is the DelegationUsage X.509 extension OID\n+//\n+// TODO(any) Replace with the real OID. This value is temporary.\n+var delegationUsageId = asn1.ObjectIdentifier{2, 5, 29, 99}\n+\n+// CreateDelegationUsagePKIXExtension returns a pkix.Extension that every delegation\n+// certificate must have.\n+func CreateDelegationUsagePKIXExtension() *pkix.Extension {\n+\treturn &pkix.Extension{\n+\t\tId:       delegationUsageId,\n+\t\tCritical: false,\n+\t\tValue:    nil,\n+\t}\n+}\n+\n+// canDelegate returns true if a certificate can be used for delegated\n+// credentials.\n+func canDelegate(cert *x509.Certificate) bool {\n+\t// Check that the digitalSignature key usage is set.\n+\tif (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 {\n+\t\treturn false\n+\t}\n+\n+\t// Check that the certificate has the DelegationUsage extension and that\n+\t// it's non-critical (per the spec).\n+\tfor _, extension := range cert.Extensions {\n+\t\tif extension.Id.Equal(delegationUsageId) {\n+\t\t\treturn true\n+\t\t}\n+\t}\n+\treturn false\n+}\n+\n+// This structure stores the public components of a credential.\n+type credential struct {\n+\tvalidTime time.Duration\n+\tpublicKey crypto.PublicKey\n+\tscheme    SignatureScheme\n+}\n+\n+// marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure\n+// (as defined in the X.509 standard) for the credential.\n+func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {\n+\tswitch cred.scheme {\n+\tcase ECDSAWithP256AndSHA256,\n+\t\tECDSAWithP384AndSHA384,\n+\t\tECDSAWithP521AndSHA512:\n+\t\tserializedPublicKey, err := x509.MarshalPKIXPublicKey(cred.publicKey)\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\treturn serializedPublicKey, nil\n+\n+\tdefault:\n+\t\treturn nil, fmt.Errorf(\"unsupported signature scheme: 0x%04x\", cred.scheme)\n+\t}\n+}\n+\n+// unmarshalSubjectPublicKeyInfo parses a DER encoded SubjectPublicKeyInfo\n+// structure into a public key and its corresponding algorithm.\n+func unmarshalSubjectPublicKeyInfo(serialized []byte) (crypto.PublicKey, SignatureScheme, error) {\n+\tpublicKey, err := x509.ParsePKIXPublicKey(serialized)\n+\tif err != nil {\n+\t\treturn nil, 0, err\n+\t}\n+\n+\tswitch pk := publicKey.(type) {\n+\tcase *ecdsa.PublicKey:\n+\t\tcurveName := pk.Curve.Params().Name\n+\t\tif curveName == \"P-256\" {\n+\t\t\treturn pk, ECDSAWithP256AndSHA256, nil\n+\t\t} else if curveName == \"P-384\" {\n+\t\t\treturn pk, ECDSAWithP384AndSHA384, nil\n+\t\t} else if curveName == \"P-521\" {\n+\t\t\treturn pk, ECDSAWithP521AndSHA512, nil\n+\t\t} else {\n+\t\t\treturn nil, 0, fmt.Errorf(\"curve %s s not supported\", curveName)\n+\t\t}\n+\n+\tdefault:\n+\t\treturn nil, 0, fmt.Errorf(\"unsupported delgation key type: %T\", pk)\n+\t}\n+}\n+\n+// marshal encodes a credential as per the spec.\n+func (cred *credential) marshal() ([]byte, error) {\n+\t// Write the valid_time field.\n+\tserialized := make([]byte, 6)\n+\tbinary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second))\n+\n+\t// Encode the public key and assert that the encoding is no longer than 2^16\n+\t// bytes (per the spect).\n+\tserializedPublicKey, err := cred.marshalSubjectPublicKeyInfo()\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tif len(serializedPublicKey) > dcMaxPublicKeyLen {\n+\t\treturn nil, errors.New(\"public key is too long\")\n+\t}\n+\n+\t// Write the length of the public_key field.\n+\tbinary.BigEndian.PutUint16(serialized[4:], uint16(len(serializedPublicKey)))\n+\n+\t// Write the public key.\n+\treturn append(serialized, serializedPublicKey...), nil\n+}\n+\n+// unmarshalCredential decodes a credential and returns it.\n+func unmarshalCredential(serialized []byte) (*credential, error) {\n+\t// Check that the serialized credential is long enough and compute the\n+\t// length of the serialized public key.\n+\tserializedPublicKeyLen, err := getCredentialLen(serialized)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tserializedPublicKeyLen -= 6\n+\n+\t// Parse the validity time.\n+\tvalidTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second\n+\n+\t// Parse the SubjectPublicKeyInfo.\n+\tserialized = serialized[6:]\n+\tpk, scheme, err := unmarshalSubjectPublicKeyInfo(serialized)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\treturn &credential{validTime, pk, scheme}, nil\n+}\n+\n+// getCredentialLen returns the number of bytes comprising the serialized\n+// credential that starts at the beginning of the input slice. It returns an\n+// error if the input is too short to contain a credential.\n+func getCredentialLen(serialized []byte) (int, error) {\n+\tif len(serialized) < 6 {\n+\t\treturn 0, errors.New(\"credential is too short\")\n+\t}\n+\t// First 4 bytes is the validity time.\n+\tserialized = serialized[4:]\n+\n+\t// The next 2 bytes are the length of the serialized public key.\n+\tserializedPublicKeyLen := int(binary.BigEndian.Uint16(serialized))\n+\tserialized = serialized[2:]\n+\n+\tif len(serialized) < serializedPublicKeyLen {\n+\t\treturn 0, errors.New(\"public key of credential is too short\")\n+\t}\n+\n+\treturn 6 + serializedPublicKeyLen, nil\n+}\n+\n+// DelegatedCredential stores a credential and its delegation.\n+type DelegatedCredential struct {\n+\t// The serialized form of the credential.\n+\tRaw []byte\n+\n+\t// Time in nonsecnds for which the credential is valid. When this data\n+\t// structure is serialized, this value is converted to a uint32 representing\n+\t// the duration in seconds.\n+\tValidTime time.Duration\n+\n+\t// The credential public key.\n+\tPublicKey crypto.PublicKey\n+\n+\t// The credential private key.\n+\tPrivateKey crypto.PrivateKey\n+\n+\t// The signature scheme associated with the credential public key.\n+\tpublicKeyScheme SignatureScheme\n+\n+\t// The signature scheme used to sign the credential.\n+\tScheme SignatureScheme\n+\n+\t// The credential's delegation.\n+\tSignature []byte\n+}\n+\n+// NewDelegatedCredential creates a new delegated credential using `cert` for\n+// delegation. It generates a public/private key pair for the provided signature\n+// algorithm (`scheme`), validity interval (defined by `cert.Leaf.notBefore` and\n+// `validTime`), and TLS version (`vers`), and signs it using `cert.PrivateKey`.\n+func NewDelegatedCredential(cert *Certificate, scheme SignatureScheme, validTime time.Duration, vers uint16) (*DelegatedCredential, error) {\n+\t// The granularity of DC validity is seconds.\n+\tvalidTime = validTime.Round(time.Second)\n+\n+\t// Parse the leaf certificate if needed.\n+\tvar err error\n+\tif cert.Leaf == nil {\n+\t\tcert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t}\n+\n+\t// Check that the leaf certificate can be used for delegation.\n+\tif !canDelegate(cert.Leaf) {\n+\t\treturn nil, errNoDelegationUsage\n+\t}\n+\n+\t// Extract the delegator signature scheme rom the certificate.\n+\tvar delegatorScheme SignatureScheme\n+\tswitch sk := cert.PrivateKey.(type) {\n+\tcase *ecdsa.PrivateKey:\n+\n+\t\t// Set scheme\n+\t\tpk := sk.Public().(*ecdsa.PublicKey)\n+\t\tcurveName := pk.Curve.Params().Name\n+\t\tcertAlg := cert.Leaf.SignatureAlgorithm\n+\t\tif certAlg == x509.ECDSAWithSHA256 && curveName == \"P-256\" {\n+\t\t\tdelegatorScheme = ECDSAWithP256AndSHA256\n+\t\t} else if certAlg == x509.ECDSAWithSHA384 && curveName == \"P-384\" {\n+\t\t\tdelegatorScheme = ECDSAWithP384AndSHA384\n+\t\t} else if certAlg == x509.ECDSAWithSHA512 && curveName == \"P-521\" {\n+\t\t\tdelegatorScheme = ECDSAWithP521AndSHA512\n+\t\t} else {\n+\t\t\treturn nil, fmt.Errorf(\n+\t\t\t\t\"using curve %s for %s is not supported\",\n+\t\t\t\tcurveName, cert.Leaf.SignatureAlgorithm)\n+\t\t}\n+\n+\tdefault:\n+\t\treturn nil, fmt.Errorf(\"unsupported delgation key type: %T\", sk)\n+\t}\n+\n+\t// Generate a new key pair.\n+\tvar sk crypto.PrivateKey\n+\tvar pk crypto.PublicKey\n+\tswitch scheme {\n+\tcase ECDSAWithP256AndSHA256,\n+\t\tECDSAWithP384AndSHA384,\n+\t\tECDSAWithP521AndSHA512:\n+\n+\t\tsk, err = ecdsa.GenerateKey(getCurve(scheme), rand.Reader)\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\tpk = sk.(*ecdsa.PrivateKey).Public()\n+\n+\tdefault:\n+\t\treturn nil, fmt.Errorf(\"unsupported signature scheme: 0x%04x\", scheme)\n+\t}\n+\n+\t// Prepare the credential for digital signing.\n+\thash := getHash(delegatorScheme)\n+\tcred := &credential{validTime, pk, scheme}\n+\tin, err := prepareDelegation(hash, cred, cert.Leaf.Raw, delegatorScheme, vers)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\n+\t// Sign the creential.","path":"subcerts.go","position":294,"original_position":297,"commit_id":"142d463d9dd3fdc02fc370cbf2dda95d6cf2592d","original_commit_id":"53f357739785ce06ddc327f4572171b63f8e15d7","user":{"login":"Bren2010","id":416022,"node_id":"MDQ6VXNlcjQxNjAyMg==","avatar_url":"https://avatars2.githubusercontent.com/u/416022?v=4","gravatar_id":"","url":"https://api.github.com/users/Bren2010","html_url":"https://github.com/Bren2010","followers_url":"https://api.github.com/users/Bren2010/followers","following_url":"https://api.github.com/users/Bren2010/following{/other_user}","gists_url":"https://api.github.com/users/Bren2010/gists{/gist_id}","starred_url":"https://api.github.com/users/Bren2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Bren2010/subscriptions","organizations_url":"https://api.github.com/users/Bren2010/orgs","repos_url":"https://api.github.com/users/Bren2010/repos","events_url":"https://api.github.com/users/Bren2010/events{/privacy}","received_events_url":"https://api.github.com/users/Bren2010/received_events","type":"User","site_admin":false},"body":"credential","created_at":"2018-06-21T20:49:10Z","updated_at":"2018-06-21T20:58:35Z","html_url":"https://github.com/cloudflare/tls-tris/pull/95#discussion_r197272564","pull_request_url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/comments/197272564"},"html":{"href":"https://github.com/cloudflare/tls-tris/pull/95#discussion_r197272564"},"pull_request":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95"}}},"pull_request":{"url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95","id":195302550,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk1MzAyNTUw","html_url":"https://github.com/cloudflare/tls-tris/pull/95","diff_url":"https://github.com/cloudflare/tls-tris/pull/95.diff","patch_url":"https://github.com/cloudflare/tls-tris/pull/95.patch","issue_url":"https://api.github.com/repos/cloudflare/tls-tris/issues/95","number":95,"state":"open","locked":false,"title":"Delegated credentials for TLS","user":{"login":"cjpatton","id":3453007,"node_id":"MDQ6VXNlcjM0NTMwMDc=","avatar_url":"https://avatars0.githubusercontent.com/u/3453007?v=4","gravatar_id":"","url":"https://api.github.com/users/cjpatton","html_url":"https://github.com/cjpatton","followers_url":"https://api.github.com/users/cjpatton/followers","following_url":"https://api.github.com/users/cjpatton/following{/other_user}","gists_url":"https://api.github.com/users/cjpatton/gists{/gist_id}","starred_url":"https://api.github.com/users/cjpatton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjpatton/subscriptions","organizations_url":"https://api.github.com/users/cjpatton/orgs","repos_url":"https://api.github.com/users/cjpatton/repos","events_url":"https://api.github.com/users/cjpatton/events{/privacy}","received_events_url":"https://api.github.com/users/cjpatton/received_events","type":"User","site_admin":false},"body":"This implements the [delegated_credential](https://tools.ietf.org/html/draft-ietf-tls-subcerts) extension for TLS 1.2 and 1.3.","created_at":"2018-06-15T23:24:07Z","updated_at":"2018-06-21T20:58:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"45b43cd88df982d078b30d883193dd5c4beaf308","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95/commits","review_comments_url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95/comments","review_comment_url":"https://api.github.com/repos/cloudflare/tls-tris/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cloudflare/tls-tris/issues/95/comments","statuses_url":"https://api.github.com/repos/cloudflare/tls-tris/statuses/142d463d9dd3fdc02fc370cbf2dda95d6cf2592d","head":{"label":"cjpatton:subcerts","ref":"subcerts","sha":"142d463d9dd3fdc02fc370cbf2dda95d6cf2592d","user":{"login":"cjpatton","id":3453007,"node_id":"MDQ6VXNlcjM0NTMwMDc=","avatar_url":"https://avatars0.githubusercontent.com/u/3453007?v=4","gravatar_id":"","url":"https://api.github.com/users/cjpatton","html_url":"https://github.com/cjpatton","followers_url":"https://api.github.com/users/cjpatton/followers","following_url":"https://api.github.com/users/cjpatton/following{/other_user}","gists_url":"https://api.github.com/users/cjpatton/gists{/gist_id}","starred_url":"https://api.github.com/users/cjpatton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjpatton/subscriptions","organizations_url":"https://api.github.com/users/cjpatton/orgs","repos_url":"https://api.github.com/users/cjpatton/repos","events_url":"https://api.github.com/users/cjpatton/events{/privacy}","received_events_url":"https://api.github.com/users/cjpatton/received_events","type":"User","site_admin":false},"repo":{"id":134472268,"node_id":"MDEwOlJlcG9zaXRvcnkxMzQ0NzIyNjg=","name":"tls-tris","full_name":"cjpatton/tls-tris","owner":{"login":"cjpatton","id":3453007,"node_id":"MDQ6VXNlcjM0NTMwMDc=","avatar_url":"https://avatars0.githubusercontent.com/u/3453007?v=4","gravatar_id":"","url":"https://api.github.com/users/cjpatton","html_url":"https://github.com/cjpatton","followers_url":"https://api.github.com/users/cjpatton/followers","following_url":"https://api.github.com/users/cjpatton/following{/other_user}","gists_url":"https://api.github.com/users/cjpatton/gists{/gist_id}","starred_url":"https://api.github.com/users/cjpatton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjpatton/subscriptions","organizations_url":"https://api.github.com/users/cjpatton/orgs","repos_url":"https://api.github.com/users/cjpatton/repos","events_url":"https://api.github.com/users/cjpatton/events{/privacy}","received_events_url":"https://api.github.com/users/cjpatton/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cjpatton/tls-tris","description":"crypto/tls, now with 100% more 1.3. THE API IS NOT STABLE AND DOCUMENTATION IS NOT GUARANTEED.","fork":true,"url":"https://api.github.com/repos/cjpatton/tls-tris","forks_url":"https://api.github.com/repos/cjpatton/tls-tris/forks","keys_url":"https://api.github.com/repos/cjpatton/tls-tris/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cjpatton/tls-tris/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cjpatton/tls-tris/teams","hooks_url":"https://api.github.com/repos/cjpatton/tls-tris/hooks","issue_events_url":"https://api.github.com/repos/cjpatton/tls-tris/issues/events{/number}","events_url":"https://api.github.com/repos/cjpatton/tls-tris/events","assignees_url":"https://api.github.com/repos/cjpatton/tls-tris/assignees{/user}","branches_url":"https://api.github.com/repos/cjpatton/tls-tris/branches{/branch}","tags_url":"https://api.github.com/repos/cjpatton/tls-tris/tags","blobs_url":"https://api.github.com/repos/cjpatton/tls-tris/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cjpatton/tls-tris/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cjpatton/tls-tris/git/refs{/sha}","trees_url":"https://api.github.com/repos/cjpatton/tls-tris/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cjpatton/tls-tris/statuses/{sha}","languages_url":"https://api.github.com/repos/cjpatton/tls-tris/languages","stargazers_url":"https://api.github.com/repos/cjpatton/tls-tris/stargazers","contributors_url":"https://api.github.com/repos/cjpatton/tls-tris/contributors","subscribers_url":"https://api.github.com/repos/cjpatton/tls-tris/subscribers","subscription_url":"https://api.github.com/repos/cjpatton/tls-tris/subscription","commits_url":"https://api.github.com/repos/cjpatton/tls-tris/commits{/sha}","git_commits_url":"https://api.github.com/repos/cjpatton/tls-tris/git/commits{/sha}","comments_url":"https://api.github.com/repos/cjpatton/tls-tris/comments{/number}","issue_comment_url":"https://api.github.com/repos/cjpatton/tls-tris/issues/comments{/number}","contents_url":"https://api.github.com/repos/cjpatton/tls-tris/contents/{+path}","compare_url":"https://api.github.com/repos/cjpatton/tls-tris/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cjpatton/tls-tris/merges","archive_url":"https://api.github.com/repos/cjpatton/tls-tris/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cjpatton/tls-tris/downloads","issues_url":"https://api.github.com/repos/cjpatton/tls-tris/issues{/number}","pulls_url":"https://api.github.com/repos/cjpatton/tls-tris/pulls{/number}","milestones_url":"https://api.github.com/repos/cjpatton/tls-tris/milestones{/number}","notifications_url":"https://api.github.com/repos/cjpatton/tls-tris/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cjpatton/tls-tris/labels{/name}","releases_url":"https://api.github.com/repos/cjpatton/tls-tris/releases{/id}","deployments_url":"https://api.github.com/repos/cjpatton/tls-tris/deployments","created_at":"2018-05-22T20:29:11Z","updated_at":"2018-06-19T16:52:11Z","pushed_at":"2018-06-21T18:26:22Z","git_url":"git://github.com/cjpatton/tls-tris.git","ssh_url":"git@github.com:cjpatton/tls-tris.git","clone_url":"https://github.com/cjpatton/tls-tris.git","svn_url":"https://github.com/cjpatton/tls-tris","homepage":"","size":138009,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"cloudflare:master","ref":"master","sha":"9557e92e524757b3af3564763f9fde457d6ecb72","user":{"login":"cloudflare","id":314135,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMxNDEzNQ==","avatar_url":"https://avatars3.githubusercontent.com/u/314135?v=4","gravatar_id":"","url":"https://api.github.com/users/cloudflare","html_url":"https://github.com/cloudflare","followers_url":"https://api.github.com/users/cloudflare/followers","following_url":"https://api.github.com/users/cloudflare/following{/other_user}","gists_url":"https://api.github.com/users/cloudflare/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudflare/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudflare/subscriptions","organizations_url":"https://api.github.com/users/cloudflare/orgs","repos_url":"https://api.github.com/users/cloudflare/repos","events_url":"https://api.github.com/users/cloudflare/events{/privacy}","received_events_url":"https://api.github.com/users/cloudflare/received_events","type":"Organization","site_admin":false},"repo":{"id":59218728,"node_id":"MDEwOlJlcG9zaXRvcnk1OTIxODcyOA==","name":"tls-tris","full_name":"cloudflare/tls-tris","owner":{"login":"cloudflare","id":314135,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMxNDEzNQ==","avatar_url":"https://avatars3.githubusercontent.com/u/314135?v=4","gravatar_id":"","url":"https://api.github.com/users/cloudflare","html_url":"https://github.com/cloudflare","followers_url":"https://api.github.com/users/cloudflare/followers","following_url":"https://api.github.com/users/cloudflare/following{/other_user}","gists_url":"https://api.github.com/users/cloudflare/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudflare/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudflare/subscriptions","organizations_url":"https://api.github.com/users/cloudflare/orgs","repos_url":"https://api.github.com/users/cloudflare/repos","events_url":"https://api.github.com/users/cloudflare/events{/privacy}","received_events_url":"https://api.github.com/users/cloudflare/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cloudflare/tls-tris","description":"crypto/tls, now with 100% more 1.3. THE API IS NOT STABLE AND DOCUMENTATION IS NOT GUARANTEED.","fork":false,"url":"https://api.github.com/repos/cloudflare/tls-tris","forks_url":"https://api.github.com/repos/cloudflare/tls-tris/forks","keys_url":"https://api.github.com/repos/cloudflare/tls-tris/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cloudflare/tls-tris/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cloudflare/tls-tris/teams","hooks_url":"https://api.github.com/repos/cloudflare/tls-tris/hooks","issue_events_url":"https://api.github.com/repos/cloudflare/tls-tris/issues/events{/number}","events_url":"https://api.github.com/repos/cloudflare/tls-tris/events","assignees_url":"https://api.github.com/repos/cloudflare/tls-tris/assignees{/user}","branches_url":"https://api.github.com/repos/cloudflare/tls-tris/branches{/branch}","tags_url":"https://api.github.com/repos/cloudflare/tls-tris/tags","blobs_url":"https://api.github.com/repos/cloudflare/tls-tris/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cloudflare/tls-tris/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cloudflare/tls-tris/git/refs{/sha}","trees_url":"https://api.github.com/repos/cloudflare/tls-tris/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cloudflare/tls-tris/statuses/{sha}","languages_url":"https://api.github.com/repos/cloudflare/tls-tris/languages","stargazers_url":"https://api.github.com/repos/cloudflare/tls-tris/stargazers","contributors_url":"https://api.github.com/repos/cloudflare/tls-tris/contributors","subscribers_url":"https://api.github.com/repos/cloudflare/tls-tris/subscribers","subscription_url":"https://api.github.com/repos/cloudflare/tls-tris/subscription","commits_url":"https://api.github.com/repos/cloudflare/tls-tris/commits{/sha}","git_commits_url":"https://api.github.com/repos/cloudflare/tls-tris/git/commits{/sha}","comments_url":"https://api.github.com/repos/cloudflare/tls-tris/comments{/number}","issue_comment_url":"https://api.github.com/repos/cloudflare/tls-tris/issues/comments{/number}","contents_url":"https://api.github.com/repos/cloudflare/tls-tris/contents/{+path}","compare_url":"https://api.github.com/repos/cloudflare/tls-tris/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cloudflare/tls-tris/merges","archive_url":"https://api.github.com/repos/cloudflare/tls-tris/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cloudflare/tls-tris/downloads","issues_url":"https://api.github.com/repos/cloudflare/tls-tris/issues{/number}","pulls_url":"https://api.github.com/repos/cloudflare/tls-tris/pulls{/number}","milestones_url":"https://api.github.com/repos/cloudflare/tls-tris/milestones{/number}","notifications_url":"https://api.github.com/repos/cloudflare/tls-tris/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cloudflare/tls-tris/labels{/name}","releases_url":"https://api.github.com/repos/cloudflare/tls-tris/releases{/id}","deployments_url":"https://api.github.com/repos/cloudflare/tls-tris/deployments","created_at":"2016-05-19T15:23:09Z","updated_at":"2018-06-20T20:58:19Z","pushed_at":"2018-06-21T18:26:25Z","git_url":"git://github.com/cloudflare/tls-tris.git","ssh_url":"git@github.com:cloudflare/tls-tris.git","clone_url":"https://github.com/cloudflare/tls-tris.git","svn_url":"https://github.com/cloudflare/tls-tris","homepage":"","size":137883,"stargazers_count":141,"watchers_count":141,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":24,"mirror_url":null,"archived":false,"open_issues_count":18,"license":null,"forks":24,"open_issues":18,"watchers":141,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95"},"html":{"href":"https://github.com/cloudflare/tls-tris/pull/95"},"issue":{"href":"https://api.github.com/repos/cloudflare/tls-tris/issues/95"},"comments":{"href":"https://api.github.com/repos/cloudflare/tls-tris/issues/95/comments"},"review_comments":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95/comments"},"review_comment":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cloudflare/tls-tris/pulls/95/commits"},"statuses":{"href":"https://api.github.com/repos/cloudflare/tls-tris/statuses/142d463d9dd3fdc02fc370cbf2dda95d6cf2592d"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"Bren2010"}}