diff --git a/README.md b/README.md index 212424f1..6f516623 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ Further information: The baseline RAINS relies on DNSSEC-style authentication that comes with inherent limitations. We seek to replace it with a new authentication architecture based on SCION end-entity PKI for better security and performance. ### Milestones -- [ ] Design documents with rationale and expected properties of the new authentication architecture as well as suggested modifications to the baseline RAINS -- [ ] Specifications of the modified and new RAINS protocols in formal language +- [x] [Design documents](https://github.com/netsys-lab/scion-rains/tree/ee-pki/docs/auth-arch) with rationale and expected properties of the new authentication architecture as well as suggested modifications to the baseline RAINS +- [x] [Specifications](https://github.com/netsys-lab/scion-rains/tree/ee-pki/docs/auth-arch/tamarin) of the modified and new RAINS protocols in formal language ## [Task 3.](https://github.com/netsys-lab/scion-rains/projects/4) Make use of DRKey system to develop mechanisms for secure and highly available RAINS communication diff --git a/cmd/rdig/rdig.go b/cmd/rdig/rdig.go index 508d7808..676b4965 100644 --- a/cmd/rdig/rdig.go +++ b/cmd/rdig/rdig.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/netsec-ethz/rains/internal/pkg/siglib" "log" "net" "strings" @@ -27,6 +28,8 @@ var expires = flag.Int64P("expires", "e", time.Now().Add(time.Second).Unix(), "expires sets the valid until timestamp of the query in unix seconds since 1970. (default current timestamp + 1 second)") var insecureTLS = flag.BoolP("insecureTLS", "i", false, "when set it does not check the validity of the server's TLS certificate. (default false)") +var rhineVerification = flag.BoolP("rhineVerify", "r", false, + "when set it does validate received assertions with the key in the rhine certificate. Adds type cert to query types. (default false)") var tok = flag.StringP("token", "t", "", "specifies a token to be used in the query instead of using a randomly generated one.") var timeout = flag.Duration("timeout", 10*time.Second, "timeout before query fails") @@ -76,6 +79,20 @@ func main() { log.Fatal("Error: default server not yet implemented. Please specify a server addr") } + // if rhineVerify set but type cert missing, add type cert + var foundcert = false + if flag.Lookup("rhineVerify").Changed && len(types) > 0 { + for _, qtype := range types { + if qtype == object.OTCertInfo { + foundcert = true + break + } + } + if !foundcert { + types = append(types, object.OTCertInfo) + } + } + var serverAddr net.Addr serverAddr, err := snet.ParseUDPAddr(fmt.Sprintf("%s:%d", server, *port)) if err != nil { @@ -103,7 +120,24 @@ func main() { if err != nil { log.Fatalf("was not able to send query: %v", err) } + fmt.Println(zonefile.IO{}.Encode(answerMsg.Content)) + + if flag.Lookup("rhineVerify").Changed { + ok := siglib.RhineCertVerification(answerMsg) + fmt.Println() + if ok { + fmt.Println("===================================") + fmt.Println("=== RHINE CERT VERIFICATION: OK ===") + fmt.Println("===================================") + + } else { + fmt.Println("================================================") + fmt.Println("=== WARNING: RHINE CERT VERIFICATION FAILED! ===") + fmt.Println("================================================") + + } + } } func parseAllQueryOptions() []query.Option { diff --git a/docs/auth-arch/README.md b/docs/auth-arch/README.md new file mode 100644 index 00000000..a083fadf --- /dev/null +++ b/docs/auth-arch/README.md @@ -0,0 +1,257 @@ +# A New Authentication Architecture for Naming Systems + +This document provides an overview of an experimental authentication architecture for Internet naming systems. + +Unlike DNSSEC-style authentication that establishes a chain of trust solely within the DNS hierarchy, the new architecture introduces external trust entities, i.e., CAs in an end-entity PKI (EE-PKI), to authenticate zone authorities. This creates unique opportunities to overcome the inherent limitations of DNSSEC in terms of security, management, and performance. + +A prototype of the new design has been implemented and integrated into the RAINS codebase. + +### Table of Contents +1. [Problem Statement](#sec-problem) +2. [Design Rationale](#sec-design) +3. [Protocols](#sec-protocol) +4. [Formal Model and Verification](#sec-formal) +5. [Prototype Implementation](#sec-prototype) + + +## Problem Statement + +### Drawbacks of DNSSEC + +Serving authentic data is the most fundamental security requirement for a naming system. DNSSEC allows zone owners to sign their DNS records and resolvers to verify the authenticity of received records. However, DNSSEC comes with several major drawbacks: + +- **Fragile trust model**. A validator must trust each level of delegation in order to verify the signed records. Any corrupted zone on the chain of trust can trick the validator to accept bogus data. When it comes to security, DNS authorities are not as prudent as professional service providers such as CAs: empirical studies show that many DNSSEC-signed zones use weak keys and algorithms [[Shulman2017]](#Shulman2017), and even the same key across multiple zones [[Chung2017]](#Chung2017). THe compromise of a zone implies the control of all its subzones, and the single root key embodies a kill switch that could potentially bring down the entire Internet [[Ben2017]](#Ben2017). + +- **High operational complexity**. DNSSEC imposes stringent consistency requirements on the authentication chain. Any inconsistency (e.g., missing or mismatching keys, signatures, algorithms, or security parameters) will fail the validation and name resolution. Such complexity with numerous corner cases to handle has caused endless implementation bugs and configuration errors, which in turn lead to frequent (and sometimes large-scale) outages at different levels of the DNS hierarchy (including the root and many TLDs)—a nightmare to every DNS practitioner [[IANIX]](#IANIX). This explains the generally perceived reluctance to deploy DNSSEC and why the adoption rate has remained unsatisfying over the years. + +- **Large performance overhead**. DNSSEC records (e.g., DNSKEY, RRSIG) are generally larger than regular records and require much more resources to process. It is estimated that, with failure cases taken into account, DNSSEC-enabled zones should prepare themselves to handle 10 times the query load and 100 times the response load of their unsigned counterparts [[Geoff2013]](#Geoff2013). A validating resolver must retrieve (if not cached) and process the entire signature chain up to the trust anchor, the cost of which might even surpass that of establishing a TLS connection. The large performance overhead also increases the risk of DoS attacks, which have already been reported in reality [[Akamai]](#Akamai). + +- **Lack of end-to-end (E2E) authentication**. As a result of the concerns above (especially the 2nd and 3rd aspect), end-users (stub resolvers) almost never validate DNSSEC-signed records in practice. They should rely on validating (recursive) resolvers to verify DNS data at best. However, DNS interception is known to be prevalent [[Liu2018]](#Liu2018), rendering the entire authentication mechanism meaningless to end users. + +We argue that these drawbacks are intrinsic to DNSSEC and they cannot be circumvented without radical architectural changes. + +### The Baseline RAINS + +RAINS was not originally designed to address the problems discussed above. The baseline RAINS essentially follows the same security architecture as DNSSEC, except the replacement of the single global root key with per-ISD root key [[SCION2017]](#SCION2017); thus, it suffers from the same set of drawbacks. This motivates us to revisit the authentication architecture of naming systems through a modern lens and to take a principled approach in designing a more robust and performant solution. + +In addition, the baseline RAINS made some design choices that we find under-optimal in retrospect. For example, RAINS treats referral data—`Redirection` (equivalent to DNS `NS` record)—as a type of `Assertion` and signs it in the residing zone. However, referral records at a zone cut should not be authoritative; signing `Redirection` offers no additional security but increases validation costs and blurs the boundary of zone authorities. We will thus also refine RAINS's data model to accommodate our new authentication architecture. + +### Our Design Goals + +1. **Robust security architecture**. The authority and security of a zone should not unconditionally hinge on any other entity including its parent and third parties. We aim at a robust system of *checks and balances* where no single entity can exert unlimited power over the namespace and take over a zone without the consent from its owner. + +2. **Resistance to operational errors**. Once securely delegated, a zone should be able to manage its keys and serve authenticated data independently from the parent zone. This avoids the synchronization along the delegation chain with strict consistency requirements imposed by DNSSEC, minimizing operational errors. + +3. **Efficient E2E authentication**. End users should be encouraged and enabled to validate, on their own, that the received data originates from the genuine zone authority and remains intact. The validation should use preferably well-established trust anchors (e.g., CA trust stores shipped with OSes or browsers) and be as efficient as possible. + + +## Design Rationale + +Our key insight is to separate the authentication of *zone authority* and the authentication of actual *zone data*. They are treated equally in DNSSEC and both performed by a validator during the *online* resolution process. Instead, we can outsource the former process to some external authority, along with the management complexity and performance overhead, and have it completed in an *offline* manner. In particular, we use an EE-PKI (hereafter, assumed to be the Web PKI) to authenticate and certify the ownership/authority of a zone. Each zone now has its RAINS Certificate (RCert) that can be used to sign zone data. This allows end users who already rely on the EE-PKI to easily validate name-resolution answers, without going through the fragile and potentially lengthy DNSSEC-style authentication chain. The figure below depicts an overview of this new architecture. + +![Architecture](figures/Architecture.png) + +It is easy to see that the design can achieve our 2nd and 3rd goal. Yet, the introduction of trusted third parties complicates the design for the 1st goal with both challenges and opportunities. We should account for different entities that may be corrupted. + +### Malicious CA + +The conventional trust model of the Web PKI is oligopoly, meaning (loosely) that any CA can issue a certificate for any domain. It would be catastrophic if our architecture allows a malicious CA to hijack arbitrary zones by issuing RCerts at will. We prevent this by reusing existing CT log infrastructure and engaging a public logger to actively verify an RCert before including it to the log. In particular, the validation consists in checking whether the RCert of zone is approved by the parent zone, which is supposed to be the legitimate owner of the child zone before the secure delegation is established. The absence of the parent's consent indicates a malicious logging attempt (by a CA) and the RCert should be rejected by the logger. By enforcing the acceptance of only logged RCerts at end users (which is already the case for regular TLS certificates), we can effectively prevent the misissuance of valid and usable RCerts. Note that special care must be taken for the top of the name hierarchy due to security and compatibility reasons. + +### Malicious DNS authority + +In DNSSEC, a zone has the ultimate control over all its subzones through the manipulation of (zone) signing keys. Hence, the compromise of the root key or TLD keys will be disastrous. It is desirable to keep a zone secure even if the superordinate zones are compromised. Our architecture for the first time enables one to achieve this challenging goal. First, we can thwart a malicious parent's attempt to obtain RCerts for an already delegated child zone by having CAs and loggers check the existence of RCerts: if a valid RCert for the child zone exists, any certificate issuance request should be rejected (unless it is a renewal request from the child zone itself within the validity period of the delegation). This requires a comprehensive view of all RCerts to be public available. Second, we can set constraints for an RCert so that it can only be used to sign data for the associated zone but not its subzones. With these mechanisms in place, a corrupted zone can at most compromise the availability but not the authenticity of the subzones. + +### Trusted Log + +We currently assume a trusted log that can provide a comprehensive view of all RCerts. The abstraction can be instantiated by a recent PKI proposal [[Laurent2022]](#Laurent2022) (also see the [implementation section](#sec-prototype)). Note that even if the logger is compromised, it cannot issue an RCert alone and so there is no direct harm to the zone. The relaxation of the assumption is left for future work. + + +## Protocols + +We have designed a set of protocols for the issuance and management of RCerts. The protocols are regarded as *offline* because they are executed only infrequently and independently of the name resolution process. The protocols run between a child zone (owner), a parent zone (owner), an CA, and a log server. Below we briefly introduce the most important protocols. + +### Initial Delegation + +The NewDlg protocol is used when a zone is delegated for the first time. The parent zone requests an RCert on behalf of the child zone, by proving to the CA and log server that it indeed has the necessary authority. + +![New Delegation Protocol](figures/NewDlg.png) + +### Certificate Update + +Once a zone has obtained its own RCert, it can manage the RCert without the need for the parent zone. The zone can renew the RCert (with the same key) directly at the CA and then add it to the log server. If the zone wants to change the public key associated with its RCert, it should follow a slightly different protocol. + +![Renew Certificate Protocol](figures/RenewCert.png) + +### Certificate Revocation + +There is also a built-in certificate revocation protocol. Note that since the log server in our design stores the revocation status for RCerts, there should be a request for a certificate owner to revoke it directly at the log server. + +![Revocation Protocol](figures/RevokeDlg.png) + + +## Formal Model and Verification + +The design of security protocols that meet expected properties is notoriously difficult, because of the complex interactions between parties and rapid exploration of state spaces that cannot be exhausted by hand. To this end, we formally modeled the NewDlg protocol (the most important among all) with a state-of-the-art theorem prover, [Tamarin](https://tamarin-prover.github.io), and successfully verified the claimed security properties. Unsurprisingly, the co-design with a formal model did help us identify latent flaws in our early hand-crafted protocol, e.g., the lack of necessary certificate verification by the parent zone. + +Note that the modeling and verification of such a protocol already require a significant amount of effort, as also suggested by the design of similar protocols (e.g., the certificate registration process in [[ARPKI]](#ARPKI). The formal analysis of all protocols pertinent to our authentication architecture goes beyond the scope of this project, and we leave this for future work. + +Please refer to [this note](tamarin/README.md) for more detail. + + +## Prototype Implementation + +We implemented a working prototype for the new authentication architecture. It consists of an online part, which enables E2E authentication of RAINS assertions with RCerts, and an offline part, which implements the above-mentioned RCert issuance and management protocols. + +### Online Name Resolution with E2E Authentication + +TODO (wait until the refactoring is done by Lou): describe the changes we make over existing RAINS + +- data model: take Redirection out from Assertion, add new RCert type + +- validation logic + +- zone file parsing + +- publisher + +### Offline Protocols + +The offline part of our prototype consists of zone managers for child and parent zones to manage RCerts, a CA server, and a logging infrastructure. The implementation is independent from the existing RAINS codebase. Below is an architectural overview of the prototype: + +![Prototype](figures/Prototype.png) + +#### Zone Manager + +The command line programs for RCert management are similar to those implementing the ACME protocol for TLS certificates, e.g., 'certbot'. The programs take in necessary arguments and send requests to the CA and/or Checker Extension. + +For example, a child zone can generate a CSR for its parent zone to use for a NewDlg request: + + $ ./ChildZoneManager NewDlg Ed25519 path/to/key.pem --zone ethz.ch + +This creates a file `ethz.ch_csr.pem` which is then used by the parent zone to obtain a certificate for the child zone: + + $ ./ParentZoneManager path/to/config.conf --NewDlg ethz.ch_csr.pem --IndSubZone=true + +In this example the parent zone would need to be `ch`. + +Once the child zone has its certificate, it can use the program to renew or revoke it (or whatever update operations supported): + + $ ./ChildZoneManager ReNewDlg Ed25519 path/to/key.pem path/to/cert.pem + $ ./ChildZoneManager RevokeDlg Ed25519 path/to/key.pem path/to/cert.pem + +Here the existing certificate is taken as input besides the keys. The program will then create a new CSR based on the existing certificate. + +Note that keys can be generated with a small key manager program that is also part of the codebase. + +#### Logging Infrastructure + +We adapt the logging infrastructure of the [F-PKI project](#Laurent2022) into our prototype. F-PKI uses a log server to store certificates in an Merkle Hash Tree (MHT), similar CT logs, and additionally a map server that provides a key-value mapping from domains to associated certificates in a sparse MHT. These components can be run as docker containers [13]. We use F-PKI client-side code to query the map-server and add certificates to the log-server. + +For the additional security checks that the log server envisioned in our design has to perform, we implement a so-called Checker Extension. The idea is to run the Checker Extension as an additional server or container, working as a reverse-proxy for the log server, since certificates should only be added after having the required checks performed. + +Therefore, the log server should only be accessible from the Checker Extension. This can be realized by having the Checker Extension run in a separate container and not exposing the log server to the external network. The map server, on the other hand, should be accessible for anyone to query all certificates (and revocations) for a specific zone. + +The Checker Extension handles certificate issuance requests from the parent-zone manager program and requests to update certificates from the certificate owner directly via the child-zone manager program. + +#### Servers and APIs + +We implement both the Checker Extension and the CA as http(s) servers providing APIs with Content-Type `application/json`. Currently the servers only run http, but https should be used for deployment. + +The following API endpoints are then provided by the CA and the Checker Extension server: + + POST https:///NewDlg + POST https:///ReNewDlg + POST https:///KeyChangeDlg + POST https:///CheckNewDlg + POST https:///CheckReNewDlg + POST https:///CheckKeyChangeDlg + POST https:///RevokeDlg + +#### Communication and Message Format + +All requests are implemented as structs in Go and encoded with JSON, a common format for web applications and also used in ACME. Binary data like certificates, certificate signing requests, keys and signatures is base64 encoded in these requests. + +The responses are also encoded as JSON objects. They only contain an error/status field and in case of the CA response also a certificate field which is populated with the base64 encoded certificate if the issuance was allowed. + +The communication model in our prototype implementation is blocking. This was chosen to keep the prototype simple and is certainly not ideal for scalability, since clients are waiting while the server is processing the request. The design and implementation of a non-blocking or asynchronous model is left for future work. + +#### Crypto Primitives + +The prototype supports two key signature schemes: RSA-PSS and Ed25519. The algorithm can be specified when running the child-zone manager program (see above). + +#### RCert Format + +The RCerts are X.509v3 certificates. An example is shown below: + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 123 (0x7b) + Signature Algorithm: ED25519 + Issuer: CN = RHINE EXAMPLE CA + Validity + Not Before: Dec 27 02:08:02 2021 GMT + Not After : Dec 18 02:08:02 2022 GMT + Subject: CN = RHINE:example.ch + Subject Public Key Info: + Public Key Algorithm: ED25519 + ED25519 Public-Key: + pub: + de:c7:27:27:85:40:b2:7e:32:7a:43:30:22:ff:64: + 68:32:8b:cb:f6:08:e7:20:3e:a0:b9:2c:f2:c9:06: + 6c:82 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Authority Key Identifier: + keyid:83:BF:BA:CE:5E:A9:01:78:92:14:09:9D:12:D8:18:ED:FC:8C:F7:48 + X509v3 Subject Alternative Name: + DNS:example.ch + Signature Algorithm: ED25519 + 91:4a:86:86:ca:eb:aa:76:3c:7f:08:89:a2:5d:85:84:ad:f6: + ed:88:2b:fa:f0:40:ab:1b:46:a9:36:f9:ff:08:11:a3:b0:46: + 38:dd:d3:ac:94:a1:a0:32:9c:41:1d:8a:48:2a:28:08:e3:c1: + 2c:db:1e:05:d4:77:b7:a6:3f:04 + +### TODO + +- The refactoring of RAINS data model with the new `Redirection` and `RCert` types +- The support of E2E data validation with RCert in the online resolution process +- Proper tools / interfaces to integrate and test the online part and offline part of RAINS + +## References + +[Shulman2017] +Haya Shulman and Michael Waidner. One key to sign them all consid- ered vulnerable: Evaluation of DNSSEC in the internet. In *Proceedings of the USENIX NSDI*, 2017. + +[Chung2017] +Taejoong Chung, Roland van Rijswijk-Deij, Balakrishnan Chan- drasekaran, David Choffnes, Dave Levin, Bruce M. Maggs, Alan Mislove, and Christo Wilson. A longitudinal, End-to-End view of the DNSSEC ecosystem. In *Proceedings of the USENIX Security*, 2017. + +[Ben2017] +Benjamin Rothenberger, Daniele E. Asoni, David Barrera, and Adrian Perrig. Internet kill switches demystified. In *Proceedings of EuroSec*, 2017. + +[IANIX] +Major dnssec outages and validation failures. . + +[Geoff2013] +Geoff Huston. Measuring dnssec performance. , 2013. + +[Akamai] +Dnssec targeted in dns reflection, amplification ddos attacks. , February 2016. + +[Liu2018] +Baojun Liu, Chaoyi Lu, Hai-Xin Duan, Ying Liu, Zhou Li, Shuang Hao, Min Yang. Who Is Answering My Queries: Understanding and Characterizing Interception of the DNS Resolution Path. In *Proceedings of the USENIX Security*, 2018. + +[SCION2017] +A. Perrig, P. Szalachowski, R. M. Reischuk, and L. Chuat. 2017. SCION: A Secure Internet Architecture. Springer Verlag. + +[ARPKI] +David A. Basin, Cas Cremers, Tiffany Hyun-Jin Kim, Adrian Perrig, Ralf Sasse, Pawel Szalachowski: ARPKI: Attack Resilient Public-Key Infrastructure. In *Proceedings of ACM CCS*, 2014. + +[Laurent2022] +Laurent Chuat, Cyrill Krähenbühl, Prateek Mittal, Adrian Perrig. F-PKI: Enabling Innovation and Trust Flexibility in the HTTPS Public-Key Infrastructure. In *Proceedings of NDSS*, 2022. + +[Wouters2021] +Paul Wouters and Wes Hardaker. The DELEGATION_ONLY DNSKEY flag. Internet-Draft draft-ietf-dnsop-delegation-only-02, Internet En- gineering Task Force, 2021. diff --git a/docs/auth-arch/figures/Architecture.png b/docs/auth-arch/figures/Architecture.png new file mode 100644 index 00000000..fe870ec1 Binary files /dev/null and b/docs/auth-arch/figures/Architecture.png differ diff --git a/docs/auth-arch/figures/NewDlg.png b/docs/auth-arch/figures/NewDlg.png new file mode 100644 index 00000000..eae1d3a7 Binary files /dev/null and b/docs/auth-arch/figures/NewDlg.png differ diff --git a/docs/auth-arch/figures/Prototype.png b/docs/auth-arch/figures/Prototype.png new file mode 100644 index 00000000..8580a758 Binary files /dev/null and b/docs/auth-arch/figures/Prototype.png differ diff --git a/docs/auth-arch/figures/RenewCert.png b/docs/auth-arch/figures/RenewCert.png new file mode 100644 index 00000000..31a25d5b Binary files /dev/null and b/docs/auth-arch/figures/RenewCert.png differ diff --git a/docs/auth-arch/figures/RevokeDlg.png b/docs/auth-arch/figures/RevokeDlg.png new file mode 100644 index 00000000..f117f394 Binary files /dev/null and b/docs/auth-arch/figures/RevokeDlg.png differ diff --git a/docs/auth-arch/tamarin/NewDlg.spthy b/docs/auth-arch/tamarin/NewDlg.spthy new file mode 100644 index 00000000..0ff79359 --- /dev/null +++ b/docs/auth-arch/tamarin/NewDlg.spthy @@ -0,0 +1,459 @@ + +// NewDlg protocol + +theory NewDlg + +begin + +functions: zone/2, csr/4 +builtins: signing + + +/* Secure channel rules */ + +rule Secure_send: + [ SOut($A, $B, m) ] --[ Send($A, $B, m) ]-> [!Secret($A, $B, m)] + +rule Secure_recv: + [ !Secret($A, $B, m) ] --[ Recv($B, $A, m) ]-> [ SIn($B, $A, m) ] + +/* Compromise Rules */ + +rule Reveal_ltk: + [ !Ltk($A, ~ltk) ] --[ Reveal($A), RevealKey($A, pk(~ltk)), Attack() ]-> [ Out(~ltk) ] + +rule Reveal_channel_outA: + [ !Secret($A, $B, m) ] --[ Reveal($A), RevealChannel($A), Attack() ]-> [ Out(m) ] + +rule Reveal_channel_outB: + [ !Secret($A, $B, m) ] --[ Reveal($B), RevealChannel($A), Attack() ]-> [ Out(m) ] + +rule Reveal_channel_in: + [ In(m) ] --[ Reveal($A), RevealChannel($A), Attack() ]-> [ !Secret($A, $B, m) ] + + +/* PKI */ + +rule Register_pk: + [ Fr(~ltk) ] + --[]-> + [ !Pk($A, pk(~ltk)) + , !Ltk($A, ~ltk) + ] + +rule Get_pk: + [ !Pk($A, pkA) ] --> [ Out(pkA) ] + +/* Child rules */ + +rule Child_Init: + [ !Ltk($C, ~skC) + , !Pk($P, pkP) + , !Pk($CA, pkCA) + , !LOGPk($LOG, pkLOG) + , Fr(~id) + ] + --[ Init('Child', $C, ~id), NotEq($P, $CA) + ]-> + [ C_St_0($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG) + ] + +rule Child_Send_CSR_To_Parent: + let + zone = zone($C, $P) + csr = csr(zone, pk(~skC), $CA, pkCA) + // zone fct captures identity of child and parent zone therefore uniquely identifying the rains zone / domain + req = <'CSR', csr, sign(csr, ~skC)> + + in + [ C_St_0($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG) + ] + --[ Start('Child', $C, pk(~skC), ~id, <$C, $P, $CA, $LOG, zone>) + // start fact is called whenever an entity sends first message or engages in the protocol for the first time + ]-> + [ C_St_1($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG, zone, req) + , SOut($C, $P, req) + ] + +rule Child_Recv_Cert_and_SCT_From_Parent: + [ C_St_1($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG, zone, req) + , SIn($C, $P, ) + ] +--[ Eq(verify(cert, <'cert', zone, pk(~skC)>, pkCA), true), Eq(verify(SCT, <'SCT', cert>, pkLOG), true), Finished('Child', $C, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Success') + ]-> + [ C_St_2($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG, zone, req, cert, SCT) + ] + +rule Child_Recv_Err_From_Parent: + [ C_St_1($C, ~id, ~skC, $P, pkP, $CA, pkCA, $LOG, pkLOG, zone, req) + , SIn($C, $P, 'Error_Parent') + + ] +--[ Finished('Child', $C, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Failed') + // finished fact is called whenever enitity sent last message or finishes an execution of the protocol + ]-> + [ + ] + + +/* Parent rules */ +rule Parent_Init: + [ !Ltk($P, ~skP) + , !LOGPk($LOG, pkLOG) + , Fr(~id) + ] + --[ Init('Parent', $P, ~id) + ]-> + [ P_St_0($P, ~id, ~skP, $LOG, pkLOG) + , IsParent($P, pk(~skP)) + ] + +rule Parent_Receive_CSR: + let + zone = zone($C, $P) + csr = csr(zone, pkC, $CA, pkCA) + req = <'CSR', csr, csrsig> + in + [ P_St_0($P, ~id, ~skP, $LOG, pkLOG) + , !Pk($CA, pkCA) + , SIn($P, $C, req) + ] + --[ Start('Parent', $P, pk(~skP), ~id, <$C, $P, $CA, $LOG, zone>) ]-> + [ P_St_1($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone) + ] + +rule Parent_Send_NewDlg_Request_to_CA: + let + payload = + NewDlgReq = + in + [ P_St_1($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone) + ] + --[ + ]-> + [ P_St_2($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone, NewDlgReq) + , SOut($P, $CA, NewDlgReq) + ] + +rule Parent_Recv_Cert_From_CA_Send_Signed_Cert_To_LOG: + let + signed_cert = sign(<'PSignedCert', cert>, ~skP) + in + [ P_St_2($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone, NewDlgReq) + , SIn($P, $CA, cert) + ] +--[ Eq(verify(cert, <'cert', zone($C, $P), pkC>, pkCA), true), ParentSignedCertForZone($P, zone($C, $P)) // TODO remove verify cert + ]-> + [ P_St_3($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone, NewDlgReq, cert, signed_cert) + , SOut($P, $LOG, ) + ] + +rule Parent_Recv_Err_From_CA_Forward_To_Child: + [ P_St_2($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone, NewDlgReq) + , SIn($P, $CA, 'Error_CA') + ] +--[ Finished('Parent', $P, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Failed') + ]-> + [ + SOut($P, $C, 'Error_Parent') + ] + +rule Parent_Recv_SCT_From_LOG_Send_To_Child: + [ P_St_3($P, ~id, ~skP, $LOG, pkLOG, $C, pkC, $CA, pkCA, req, zone, NewDlgReq, cert, signed_cert) + , SIn($P, $LOG, SCT) + ] +--[ Eq(verify(SCT, <'SCT', cert>, pkLOG), true), Finished('Parent', $P, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Success') + ]-> + [ SOut($P, $C, ) + ] + +/* CA rules */ + +rule CA_Init: + [ !Ltk($CA, ~skCA) + , !LOGPk($LOG, pkLOG) + , Fr(~id) + ] +--[ Init('CA', $CA, ~id) + , IsCA(pk(~skCA)) + ]-> + [ CA_St_0($CA, ~id, ~skCA, $LOG, pkLOG) + , !CA(pk(~skCA)) + ] + + +rule CA_Receive_Request_From_Parent_And_Check_LOG: + let + zone = zone($C, $P) + csr = csr(zone, pkC, $CA, pkCA) + req = <'CSR', csr, csrsig> + payload = + NewDlgReq = + in + [ CA_St_0($CA, ~id, ~skCA, $LOG, pkLOG) + , SIn($CA, $P, NewDlgReq) + , !AuthenticParent($P, pkP) + ] +--[Eq(verify(sig, payload, pkP), true), Eq(verify(csrsig, csr, pkC), true), Start('CA', $CA, pk(~skCA), ~id, <$C, $P, $CA, $LOG, zone>) + ]-> + [ CA_St_1($CA, ~id, ~skCA, $LOG, pkLOG, $P, pkP, $C, pkC, req, NewDlgReq, zone) + , SOut($CA, $LOG, <'RequestInfo', zone>) + ] + + +rule CA_Check_OK_Send_Cert_To_Parent: + let + cert = sign(<'cert', zone, pkC>, ~skCA) + in + [ CA_St_1($CA, ~id, ~skCA, $LOG, pkLOG, $P, pkP, $C, pkC, req, NewDlgReq, zone) + , SIn($CA, $LOG, <<'OK', zone>, sig>) + ] +--[ Eq(verify(sig, <'OK', zone>, pkLOG), true), Finished('CA', $CA, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Success') + ]-> + [ SOut($CA, $P, cert) + ] + +rule CA_Check_NOT_OK_Send_Err_To_Parent: + [ CA_St_1($CA, ~id, ~skCA, $LOG, pkLOG, $P, pkP, $C, pkC, req, NewDlgReq, zone) + , SIn($CA, $LOG, <<'NOTOK', zone>, sig>) + ] +--[ Eq(verify(sig, <'NOTOK', zone>, pkLOG), true), Finished('CA', $CA, ~id, <$C, $P, $CA, $LOG, req, zone>, 'Failed') + ]-> + [ SOut($CA, $P, 'Error_CA') + ] + + + +/* LogServer Rules */ + + +rule LOG_Init: + [ !Ltk($LOG, ~skLOG) + , !Pk($LOG, pkLOG) + , Fr(~id) + ] +--[ Init('LOG', $LOG, ~id), Unique($LOG), Unique(~skLOG) , Unique('OneLog')// only one logserver + ]-> + [ !LOG_St_0($LOG, ~id, ~skLOG) + , !LOGPk($LOG, pkLOG) + ] + +rule LOG_Answer_Check_Ok: + let + zone = zone($C, $P) + in + [ !LOG_St_0($LOG, ~id, ~skLOG) + , SIn($LOG, $CA, <'RequestInfo', zone>) + ] + --[NoConflictAtCheck(zone)]-> + // NoConflictAtCheck(zone) states that a conflict check was performed by a CA and the log responded with OK which means no conflicting + // certificates exist for that zone + [ + SOut($LOG, $CA, <<'OK', zone>, sign(<'OK', zone>, ~skLOG)>) + ] + + +rule LOG_Answer_Check_NotOk: + let + zone = zone($C, $P) + in + [ !LOG_St_0($LOG, ~id, ~skLOG) + , SIn($LOG, $CA, <'RequestInfo', zone>) + ] + --[ConflictAtCheck(zone)]-> + // ConflictAtCheck(zone) states that a conflict check was performed by a CA and the log responded with NOTOK which means a conflicting + // certificate exists for that zone + [ + SOut($LOG, $CA, <<'NOTOK', zone>, sign(<'NOTOK', zone>, ~skLOG)>) + ] + + +rule LOG_Process_Request_From_Parent: + let + cert = sign(<'cert', zone($C, $P), pkC>, ~skCA) + SCT = sign(<'SCT', cert>, ~skLOG) + in + [ !LOG_St_0($LOG, ~id, ~skLOG) + , SIn($LOG, $P, ) + , !CA(pk(~skCA)) + , !AuthenticParent($P, pkP) + ] +--[Eq(verify(signed_cert, <'PSignedCert', cert>, pkP), true), CertForZoneInLog(zone($C, $P)), NotEq(pkP, pk(~skCA)) + // CertForZoneInLog captures the point where a certificate for some zone was added to the log + ]-> + [ SOut($LOG, $P, SCT) + ] + + +/* Event Rules */ + +rule ExistingCertInLog: + [ + !Pk($C, Ckey) + , !Pk($P, Pkey) + ] + --[Unique('Event'), Event(), Unique($P), ParentAuthenticated($P, Pkey), CertForZoneInLog(zone($C, $P))]-> + [!AuthenticParent($P, Pkey)] + + +rule ParentAuthentication: + [IsParent($P, pkP)] + --[Unique($P), ParentAuthenticated($P, pkP)]-> + [!AuthenticParent($P, pkP)] + + + + +/* Restrictions */ + +restriction Equality: + "All x y #i. Eq(x, y)@i ==> x = y" + +restriction InEquality: + "All x y #i. NotEq(x, y)@i ==> not(x = y)" + +restriction Uniqueness: + "All x #i #j. Unique(x)@i & Unique(x)@j ==> #i = #j" + +restriction AbsenceCheck1: +"All zone #i #j. CertForZoneInLog(zone)@i & NoConflictAtCheck(zone)@j & i < j ==> F" + +restriction AbsenceCheck2: + "All zone #i. ConflictAtCheck(zone)@i ==> (Ex #j. CertForZoneInLog(zone)@j & j < i)" + +restriction LogNeverCompromised: + "All LOG id #i. Init('LOG', LOG, id)@i & (Ex #c. Reveal(LOG)@c) ==> F" + +restriction InvalidZone: + "All C P #i. CertForZoneInLog(zone(C, P))@i ==> (not(C = P))" + +restriction CACanNotBeAuthenticParent: +"All #i #j P key. ParentAuthenticated(P, key)@i & IsCA(key)@j ==> F" + + +// This restriction limits all roles to one Init except the log server. Can be used to make smaller model +// restriction LimitModelToOneInitPerRole: + // "All role X Y idX idY #j #k. Init(role, X, idX)@j & Init(role, Y, idY)@k ==> ((#j = #k) | role = 'LOG')" + + // shows successful execution trace of NewDlg + lemma ChildFinishSuccess: + exists-trace + "Ex C id t #i. Finished('Child', C, id, t, 'Success')@i + & (All role X Y idX idY #j #k. + Init(role, X, idX)@j & Init(role, Y, idY)@k + ==> ((#j = #k)) + ) + & (All role #l. Reveal(role)@l ==> F) + & not(Ex #e. Event()@e) + " + +// shows failed execution trace of NewDlg (requires 2 runs of the protocol) +lemma ChildFinishFailed: + exists-trace + "Ex C id t #i. Finished('Child', C, id, t, 'Failed')@i + & (All role X Y idX idY #j #k. + Init(role, X, idX)@j & Init(role, Y, idY)@k + ==> (X = Y) + ) + & (All role X idX1 idX2 idX3 #j #k #l. + Init(role, X, idX1)@j & Init(role, X, idX2)@k & Init(role, X, idX3)@l + ==> ((#j = #k) | (#j = #l) | (#k = #l)) + ) + & (All role #l. Reveal(role)@l ==> F) + & not(Ex #e. Event()@e) + " + + +lemma agreement: +all-traces +"All C id P req zone CA LOG #i. + Finished('Child', C, id, , 'Success')@i + & not(Ex #e. Event()@e) + ==> (Ex id2 #j. Finished('Parent', P, id2, , 'Success')@j) | (Ex #c. Reveal(P)@c) | (Ex #c. Reveal(C)@c) +" + +// Child finishing protocol successfully implies cert has been added to log or child was compromised +lemma AddedToLog: + all-traces + "All C id P CA LOG req #i. + Finished('Child', C, id, , 'Success')@i + & not(Ex #e. Event()@e) + ==> (Ex #j. CertForZoneInLog(zone(C, P))@j) | (Ex #c. Attack()@c) + " + +// If a cert for a zone was added to log, parent needs to have signed it or parent was comrpomised. +lemma CompromisedParent: + all-traces + "All C P #i. + CertForZoneInLog(zone(C, P))@i + & not(Ex #e. Event()@e) + ==> (Ex #j. ParentSignedCertForZone(P, zone(C, P))@j) | (Ex #c. Reveal(P)@c) + " + +// If a cert was added to log, child needs to have started protocol at some point or it was compromised, or parent (channel) was compromised +lemma MaliciousParent: + all-traces + "All C P #i. + CertForZoneInLog(zone(C, P))@i + & not(Ex #e. Event()@e) + ==> (Ex idC keyC CA LOG #j. Start('Child', C, keyC, idC, )@j) + | (Ex #c. Reveal(P)@c) + | (Ex #c. Reveal(C)@c) + " + +// If cert for zone added to log, child and parent started protocol at some point before or they are compromised +lemma correctness: + all-traces + "All C P #i. + CertForZoneInLog(zone(C, P))@i + & not(Ex #e. Event()@e) + ==> (Ex CA LOG idC idP keyC keyP #j #k. Start('Child', C, keyC, idC, )@j + & Start('Parent', P, keyP, idP, )@k) + | (Ex #c. Reveal(P)@c) | (Ex #c. Reveal(C)@c) + " + +lemma NoConflictingCertsInLog: +// ATTACK: race condition, two overlapping executions of NewDlg protocol , TODO write as exists-trace with only 1 init of child/parent + all-traces + "All zone #i #j. CertForZoneInLog(zone)@i & CertForZoneInLog(zone)@j ==> ((#i = #j) | (Ex #e. Event()@e) | (Ex #c. Attack()@c)) " + + + +// If cert for zone exists and no comprmomise has taken place so far then: +// It is not possible to for anyone to obtain a second certificate for that zone while only the parent is compromised + +// TODO prove without bound!! + +lemma Property: + all-traces + "All C P Pkey #i. CertForZoneInLog(zone(C, P))@i & ParentAuthenticated(P, Pkey)@i + & not(Ex #c idc. (#c < #i) & Init('Child', C, idc)@c) + & not(Ex #p idp. (#p < #i) & Init('Parent', P, idp)@p) + & not(Ex #a. (#a < #i) & Attack()@a) + // & (All A #r. (#i < #r) & Reveal(A)@r ==> (A = P)) + & (All A Akey #r. (#i < #r) & RevealKey(A, Akey)@r ==> (A = P) & (Akey = Pkey)) + & (All role X Y idX idY #j #k. + Init(role, X, idX)@j & Init(role, Y, idY)@k + ==> ((#j = #k)) + ) + ==> + not(Ex #c. (i < c) & CertForZoneInLog(zone(C, P))@c)" + + +// If cert for zone exists and no comprmomise has taken place so far then: +// It is not possible to for anyone to obtain a second certificate for that zone while the parent (and log server) are not compromised and +// the parent is not starting the protocol (due to out of band auth with child) + +lemma Property2: +all-traces + "All C P Pkey #i. CertForZoneInLog(zone(C, P))@i & ParentAuthenticated(P, Pkey)@i + & not(Ex #c idc. (#c < #i) & Init('Child', C, idc)@c) + & not(Ex #p idp. (#p < #i) & Init('Parent', P, idp)@p) + & not(Ex #a. (#a < #i) & Attack()@a) + //& (All A #r. (#i < #r) & Reveal(A)@r ==> not(A = P)) + & (All A Akey #r. (#i < #r) & RevealKey(A, Akey)@r ==> not(A = P) & not(Akey = Pkey)) + & not(Ex idpp CA LOG #s. Start('Parent', P, Pkey, idpp, )@s) + ==> + not(Ex #c. (i < c) & CertForZoneInLog(zone(C, P))@c)" + +end diff --git a/docs/auth-arch/tamarin/README.md b/docs/auth-arch/tamarin/README.md new file mode 100644 index 00000000..7d60c807 --- /dev/null +++ b/docs/auth-arch/tamarin/README.md @@ -0,0 +1,113 @@ +# Tamarin model + +Here's a summary of the Tamarin [model](NewDlg.spthy) for the [NewDlg protocol](../figures/NewDlg.png). + +### Model / Rules: + +4 entities: child, parent, ca, log + +child, parent, ca are in different states of the protocol: modeled with state facts e.g. `C_St_1()` + +log server only has one init and then produces a persistent state fact. + +Before init, public key is generated with `Register_pk` rule. Note that there is no `Unique()` fact for the identity. + +Child and Parent have an Identity: `C`, `P` and a public key `Ckey`, `Pkey`. +The identity is their zone, so for instance `ethz = C` , `ch = P` for zone `ethz.ch` + +Since there can be multiple parents (with different keys) for the same `P`, there is a `ParentAuthentication` rule. +This rule has the `Unique` fact so we assume only ever one authentic parent for a zone. Otherwise properties like obtaining a 2nd certificate for +an independent childzone can be broken with a second authentic parent. In the real protocol an attacker can not produce another authentic parent +either. Even a malicious CA can not do that by signing a certificate for the parent because by induction it also needs a certificate for that parent +and some parent will eventually be authenticated via dnssec instead of a certificate. (Root and TLDs) + + +### Channels : + +Secure channels are modeled with `Secure_send` and `Secure_recv`. +But in the reveal rules we differentiate by revealing a channel or a key. So we can prove lemmas only requiring that +a key must not be compromised essentially allowing insecure channels. + +### Restrictions: + +The log is never compromised in our model. Besides the restricion `LogNeverCompromised` +we have two restricions `AbsenceCheck1` and `AbsenceCheck2`. These make sure that the log always answers correctly to +a CAs query for certificates for a certain zone. + + +###Lemmas: + +**sanity checks**: `ChildFinishSuccess`, `ChildFinishFailed` (first register a cert, then try to register another) + +**Property1 and 2** are the lemmas we are interested about that should capture our security goals for this system. + +All other lemmas are not really useful, can be considered as more sanitiy checks mabye. + + +**Property1 states**: If there exists a cert for `C`,`P` in the log and the authentic parent `P`, `Pkey` exists, and no entitiy has been compromised so far then: +It is not possible to get another cert for `C`,`P` into the log if only the `Pkey` is revealed (this means also CA key can not be revealed, channels can). + +This is supposed to capture malicious or compromised parents who should not be able to get a second certificate in our design. The parent can not get a second certificate from a CA and therefore can not pass the log server check. +The parent could just sing the certificate itself , acting as the CA, which is why we have the `!CA()` fact after a CA init. The log server checks this. + +**Note Property1: Bound:** +``` +& (All role X Y idX idY #j #k. +Init(role, X, idX)@j & Init(role, Y, idY)@k +==> ((#j = #k)) +) +``` +It would be nice to prove propery1 without this bound. + +**Property2 states:** If there exists a cert for `C`,`P` in the log and the authentic parent `P`, `Pkey` exists, and no entitiy has been compromised so far then: +It is not possible to get another cert for `C`,`P` into the log if `Pkey` is not revealed (other keys can be revealed (CA) + chanels too ) AND the parent has not started the +protocl for `C`,`P` . + +This lemma is supposed to capture malicious or compromised CAs. Without the parent being compromised too they should not be able to put a second certificate in the log. +The parent could also be malicious, essentially just executing the protocol with the certificate from the compromised CA. An honest parent wouldn't do that which is why we need the assumption `not(Started('Parent', C, P))` too. + + +**Note Property1+2:** +The `not(Init())` statements in property1 and 2 make sure that the existing certificate in the log is generated with the "event" rule `ExistingCertInLog`. And make sure there are no unfinished protocol executions in the model that the attacker could consider. + + + + +### attacks in general : + +For an attack (getting a second certificate for an existing independent subzone) we need the authentic parent signing the request as well as a CA signing the request. A CA needs to be compromised for that because a honest CA is always listenting to the answer from the log (conflict exists) and not signing a certificate. +The parent could just act as CA, essentially signing the certificate itself, which is why we have the `!CA()` fact after a CA init rule. + +If the model allows a compromised CA, then an attack is possible with a malicious parent, because the model does not know that an honest parent wouldn't start the protocol or sign a request for an existing independent child. This is why property 2 has the states that the parent has not started the protocol with C, P . + + +### other attacks ( `NoConflictingCertsInLog` lemma which falsifies) : + +A parent sends to messages two a CA, both before sending a message to the log to add the certificates. The CAs will respond with no conflict in both cases, now the parent +has two certificates to add to the log. + +In the real world this could very well be used by a parent to create a second certificate for themself. This is why we have the assumption that before a child zone has obtained a cert, no entity was malicious or compromised. + + +### OUTPUT: + +`tamarin-prover --prove NewDlg.spthy` + +```` +============================================================================== +summary of summaries: + +analyzed: NewDlg.spthy + +ChildFinishSuccess (exists-trace): verified (12 steps) +ChildFinishFailed (exists-trace): verified (29 steps) +agreement (all-traces): verified (96 steps) +AddedToLog (all-traces): verified (9 steps) +CompromisedParent (all-traces): verified (10 steps) +MaliciousParent (all-traces): verified (37 steps) +correctness (all-traces): verified (37 steps) +NoConflictingCertsInLog (all-traces): falsified - found trace (29 steps) +Property (all-traces): verified (6960 steps) +Property2 (all-traces): verified (6649 steps) + +============================================================================== diff --git a/docs/man/rdig.md b/docs/man/rdig.md index 61b82d61..38df75c6 100644 --- a/docs/man/rdig.md +++ b/docs/man/rdig.md @@ -38,6 +38,8 @@ where: (default current timestamp + 1 second) * `-i`, `--insecureTLS`: when set it does not check the validity of the server's TLS certificate. (default false) +* `-r`, `--rhineVerify`: when set it does validate received assertions with the key in the rhine certificate. Adds type `cert` to query types if not added. + (default false) * `-t`, `--token`: specifies a token to be used in the query instead of using a randomly generated one. diff --git a/docs/zonefile-format.md b/docs/zonefile-format.md index dec9e654..a7d517a1 100644 --- a/docs/zonefile-format.md +++ b/docs/zonefile-format.md @@ -56,8 +56,8 @@ comments. There are three special encodings: ":nameset:" | ":cert:" | ":srv:" | ":regr:" | ":regt:" | ":infra:" | ":extra:" | ":next:" | ::= | - ::= ":unspecified:" | ":tls:" - ::= ":trustAnchor:" | ":endEntity:" + ::= ":unspecified:" | ":tls:" | ":rhine:" + ::= ":trustAnchor:" | ":endEntity:" | ":zoneAuth:" ::= ":noHash:" | ":sha256:" | ":sha384:" | ":sha512:" | ":fnv64:" | ":murmur364:" ::= ":standard:" | ":km1:" | ":km2:" ::= "(" ")" diff --git a/internal/pkg/object/certificateusage_string.go b/internal/pkg/object/certificateusage_string.go index 7c7e0461..45ac562a 100644 --- a/internal/pkg/object/certificateusage_string.go +++ b/internal/pkg/object/certificateusage_string.go @@ -10,16 +10,26 @@ func _() { var x [1]struct{} _ = x[CUTrustAnchor-2] _ = x[CUEndEntity-3] + _ = x[CUZoneAuth-5] } -const _CertificateUsage_name = "CUTrustAnchorCUEndEntity" +const ( + _CertificateUsage_name_0 = "CUTrustAnchorCUEndEntity" + _CertificateUsage_name_1 = "CUZoneAuth" +) -var _CertificateUsage_index = [...]uint8{0, 13, 24} +var ( + _CertificateUsage_index_0 = [...]uint8{0, 13, 24} +) func (i CertificateUsage) String() string { - i -= 2 - if i < 0 || i >= CertificateUsage(len(_CertificateUsage_index)-1) { - return "CertificateUsage(" + strconv.FormatInt(int64(i+2), 10) + ")" + switch { + case 2 <= i && i <= 3: + i -= 2 + return _CertificateUsage_name_0[_CertificateUsage_index_0[i]:_CertificateUsage_index_0[i+1]] + case i == 5: + return _CertificateUsage_name_1 + default: + return "CertificateUsage(" + strconv.FormatInt(int64(i), 10) + ")" } - return _CertificateUsage_name[_CertificateUsage_index[i]:_CertificateUsage_index[i+1]] } diff --git a/internal/pkg/object/object.go b/internal/pkg/object/object.go index e314995a..cbec6ad0 100644 --- a/internal/pkg/object/object.go +++ b/internal/pkg/object/object.go @@ -661,6 +661,7 @@ type ProtocolType int const ( PTUnspecified ProtocolType = 0 PTTLS ProtocolType = 1 + PTRhine ProtocolType = 4 ) //CertificateUsage is an identifier for a certificate usage. The ID is chosen according to the RAINS Protocol Specification. @@ -670,6 +671,7 @@ type CertificateUsage int const ( CUTrustAnchor CertificateUsage = 2 CUEndEntity CertificateUsage = 3 + CUZoneAuth CertificateUsage = 5 ) //ServiceInfo contains information how to access a named service diff --git a/internal/pkg/object/protocoltype_string.go b/internal/pkg/object/protocoltype_string.go index 3fbed47a..c9b473e3 100644 --- a/internal/pkg/object/protocoltype_string.go +++ b/internal/pkg/object/protocoltype_string.go @@ -10,15 +10,25 @@ func _() { var x [1]struct{} _ = x[PTUnspecified-0] _ = x[PTTLS-1] + _ = x[PTRhine-4] } -const _ProtocolType_name = "PTUnspecifiedPTTLS" +const ( + _ProtocolType_name_0 = "PTUnspecifiedPTTLS" + _ProtocolType_name_1 = "PTRhine" +) -var _ProtocolType_index = [...]uint8{0, 13, 18} +var ( + _ProtocolType_index_0 = [...]uint8{0, 13, 18} +) func (i ProtocolType) String() string { - if i < 0 || i >= ProtocolType(len(_ProtocolType_index)-1) { + switch { + case 0 <= i && i <= 1: + return _ProtocolType_name_0[_ProtocolType_index_0[i]:_ProtocolType_index_0[i+1]] + case i == 4: + return _ProtocolType_name_1 + default: return "ProtocolType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _ProtocolType_name[_ProtocolType_index[i]:_ProtocolType_index[i+1]] } diff --git a/internal/pkg/siglib/rainsSiglib.go b/internal/pkg/siglib/rainsSiglib.go index a1868575..52de144f 100644 --- a/internal/pkg/siglib/rainsSiglib.go +++ b/internal/pkg/siglib/rainsSiglib.go @@ -5,6 +5,7 @@ package siglib import ( "bytes" + "crypto/x509" "fmt" "regexp" "time" @@ -388,3 +389,78 @@ func updateSectionValidity(sec section.WithSig, pkeyValidSince, pkeyValidUntil, } } } + +func RhineCertVerification(msg message.Message) bool { + + // look for rhine cert + var rhinecert *x509.Certificate = nil + var pubkey interface{} + var zone string + var id keys.PublicKeyID + + for _, s := range msg.Content { + switch s := s.(type) { + case *section.Assertion: + rhinecert, zone, id = util.GetRhineCertFromAssertion(s) + if rhinecert != nil { + break + } + case *section.Zone: + assertions := s.Content + for _, a := range assertions { + rhinecert, zone, id = util.GetRhineCertFromAssertion(a) + if rhinecert != nil { + break + } + } + } + } + + if rhinecert == nil { + log.Warn("No RCert returned") + return false + } + + // TODO + var CaCertPool *x509.CertPool + CaCertPool, _ = x509.SystemCertPool() + + CaCertPool.AppendCertsFromPEM([]byte("-----BEGIN CERTIFICATE-----\nMIIBJjCB2aADAgECAgEBMAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF\nIENBMB4XDTIyMDIyMTA5MDI1NVoXDTIzMDIxMjA5MDI1NVowGzEZMBcGA1UEAxMQ\nUkhJTkUgRVhBTVBMRSBDQTAqMAUGAytlcAMhAFq9YoSG/zv2npflvTwmog9Ymijs\nK0NDTDYFgTbGxyrto0IwQDAOBgNVHQ8BAf8EBAMCAoQwDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUXcJH29E2egUuSdhJFoy/kJQDlcwwBQYDK2VwA0EAxB2JHVh+\nN7o3RTBCp7wOWDlGePd0xuhRhU4GEJs4CTxGgLbcyX1iIzF7kJ1qCmp+y180PAJe\nxqM22eY3hKQFAQ==\n-----END CERTIFICATE-----")) + + _, err := rhinecert.Verify(x509.VerifyOptions{ + DNSName: zone, + Roots: CaCertPool, + }) + if err != nil { + log.Warn("RCert invalid") + return false + } + pubkey = rhinecert.PublicKey + + // verify assertions + + MaxCacheVal := util.MaxCacheValidity{ + AssertionValidity: 3 * time.Hour, + ShardValidity: 3 * time.Hour, + PshardValidity: 3 * time.Hour, + ZoneValidity: 3 * time.Hour, + } + + rainskey := keys.PublicKey{ + PublicKeyID: id, + ValidSince: rhinecert.NotBefore.Unix(), + ValidUntil: time.Now().Add(time.Hour * 3).Unix(), + Key: pubkey, + } + pkeys := make(map[keys.PublicKeyID][]keys.PublicKey) + pkeys[id] = []keys.PublicKey{rainskey} + for _, s := range msg.Content { + sec := s.(section.WithSigForward) + if !CheckSectionSignatures(sec, pkeys, MaxCacheVal) { + log.Error("Invalid Assertion Signature for RCert") + return false + } + } + + return true +} diff --git a/internal/pkg/util/rainslibUtil.go b/internal/pkg/util/rainslibUtil.go index ce13096d..64c06b37 100644 --- a/internal/pkg/util/rainslibUtil.go +++ b/internal/pkg/util/rainslibUtil.go @@ -1,6 +1,7 @@ package util import ( + "crypto/x509" "encoding/gob" "errors" "fmt" @@ -177,3 +178,34 @@ func GetOverlapValidityForSignatures(sigs []signature.Sig) (int64, int64) { } return bySince[0].ValidSince, until } + +func GetRhineCertFromAssertion(s *section.Assertion) (rhinecert *x509.Certificate, zone string, id keys.PublicKeyID) { + objs := s.Content + + for _, obj := range objs { + if obj.Type == object.OTCertInfo { + cert, ok := obj.Value.(object.Certificate) + if ok { + if cert.Type != object.PTRhine { + continue + } + if cert.Usage != object.CUZoneAuth { + continue + } + var err error + rhinecert, err = x509.ParseCertificate(cert.Data) + if err != nil { + continue + } + zone = s.SubjectZone + id = s.Signatures[0].PublicKeyID + return rhinecert, zone, id + + } else { + continue + } + } + } + return nil, "", keys.PublicKeyID{} + +} diff --git a/internal/pkg/zonefile/y.output b/internal/pkg/zonefile/y.output new file mode 100644 index 00000000..072f705a --- /dev/null +++ b/internal/pkg/zonefile/y.output @@ -0,0 +1,1315 @@ + +state 0 + $accept: .top $end + sections: . (2) + + . reduce 2 (src line 191) + + sections goto 2 + top goto 1 + +state 1 + $accept: top.$end + + $end accept + . error + + +state 2 + top: sections. (1) + sections: sections.assertion + sections: sections.shard + sections: sections.pshard + sections: sections.zone + + assertionType shift 11 + shardType shift 12 + pshardType shift 13 + zoneType shift 14 + . reduce 1 (src line 186) + + zone goto 6 + zoneBody goto 10 + shard goto 4 + shardBody goto 8 + pshard goto 5 + pshardBody goto 9 + assertion goto 3 + assertionBody goto 7 + +state 3 + sections: sections assertion. (3) + + . reduce 3 (src line 195) + + +state 4 + sections: sections shard. (4) + + . reduce 4 (src line 199) + + +state 5 + sections: sections pshard. (5) + + . reduce 5 (src line 203) + + +state 6 + sections: sections zone. (6) + + . reduce 6 (src line 207) + + +state 7 + assertion: assertionBody. (31) + assertion: assertionBody.annotation + + lParenthesis shift 16 + . reduce 31 (src line 337) + + annotation goto 15 + +state 8 + shard: shardBody. (12) + shard: shardBody.annotation + + lParenthesis shift 16 + . reduce 12 (src line 237) + + annotation goto 17 + +state 9 + pshard: pshardBody. (21) + pshard: pshardBody.annotation + + lParenthesis shift 16 + . reduce 21 (src line 281) + + annotation goto 18 + +state 10 + zone: zoneBody. (7) + zone: zoneBody.annotation + + lParenthesis shift 16 + . reduce 7 (src line 212) + + annotation goto 19 + +state 11 + assertionBody: assertionType.ID lBracket objects rBracket + assertionBody: assertionType.ID ID ID lBracket objects rBracket + + ID shift 20 + . error + + +state 12 + shardBody: shardType.ID ID shardRange lBracket shardContent rBracket + + ID shift 21 + . error + + +state 13 + pshardBody: pshardType.ID ID shardRange bfAlgo bfHash ID + + ID shift 22 + . error + + +state 14 + zoneBody: zoneType.ID ID lBracket zoneContent rBracket + + ID shift 23 + . error + + +state 15 + assertion: assertionBody annotation. (32) + + . reduce 32 (src line 338) + + +state 16 + annotation: lParenthesis.annotationBody rParenthesis + + sigType shift 27 + . error + + annotationBody goto 24 + signature goto 25 + signatureMeta goto 26 + +state 17 + shard: shardBody annotation. (13) + + . reduce 13 (src line 238) + + +state 18 + pshard: pshardBody annotation. (22) + + . reduce 22 (src line 282) + + +state 19 + zone: zoneBody annotation. (8) + + . reduce 8 (src line 213) + + +state 20 + assertionBody: assertionType ID.lBracket objects rBracket + assertionBody: assertionType ID.ID ID lBracket objects rBracket + + ID shift 29 + lBracket shift 28 + . error + + +state 21 + shardBody: shardType ID.ID shardRange lBracket shardContent rBracket + + ID shift 30 + . error + + +state 22 + pshardBody: pshardType ID.ID shardRange bfAlgo bfHash ID + + ID shift 31 + . error + + +state 23 + zoneBody: zoneType ID.ID lBracket zoneContent rBracket + + ID shift 32 + . error + + +state 24 + annotation: lParenthesis annotationBody.rParenthesis + annotationBody: annotationBody.signature + + sigType shift 27 + rParenthesis shift 33 + . error + + signature goto 34 + signatureMeta goto 26 + +state 25 + annotationBody: signature. (97) + + . reduce 97 (src line 669) + + +state 26 + signature: signatureMeta. (99) + signature: signatureMeta.ID + + ID shift 35 + . reduce 99 (src line 678) + + +state 27 + signatureMeta: sigType.ed25519Type rains ID ID ID + + ed25519Type shift 36 + . error + + +state 28 + assertionBody: assertionType ID lBracket.objects rBracket + + nameType shift 53 + ip4Type shift 55 + ip6Type shift 54 + scionType shift 56 + redirType shift 57 + delegType shift 58 + namesetType shift 59 + certType shift 60 + srvType shift 61 + regrType shift 62 + regtType shift 63 + infraType shift 64 + extraType shift 65 + nextType shift 66 + . error + + objects goto 37 + object goto 38 + name goto 39 + ip4 goto 41 + ip6 goto 40 + scion goto 42 + redir goto 43 + deleg goto 44 + nameset goto 45 + cert goto 46 + srv goto 47 + regr goto 48 + regt goto 49 + infra goto 50 + extra goto 51 + next goto 52 + +state 29 + assertionBody: assertionType ID ID.ID lBracket objects rBracket + + ID shift 67 + . error + + +state 30 + shardBody: shardType ID ID.shardRange lBracket shardContent rBracket + + ID shift 69 + rangeBegin shift 70 + . error + + shardRange goto 68 + +state 31 + pshardBody: pshardType ID ID.shardRange bfAlgo bfHash ID + + ID shift 69 + rangeBegin shift 70 + . error + + shardRange goto 71 + +state 32 + zoneBody: zoneType ID ID.lBracket zoneContent rBracket + + lBracket shift 72 + . error + + +state 33 + annotation: lParenthesis annotationBody rParenthesis. (96) + + . reduce 96 (src line 664) + + +state 34 + annotationBody: annotationBody signature. (98) + + . reduce 98 (src line 673) + + +state 35 + signature: signatureMeta ID. (100) + + . reduce 100 (src line 679) + + +state 36 + signatureMeta: sigType ed25519Type.rains ID ID ID + + rains shift 73 + . error + + +state 37 + assertionBody: assertionType ID lBracket objects.rBracket + objects: objects.object + + nameType shift 53 + ip4Type shift 55 + ip6Type shift 54 + scionType shift 56 + redirType shift 57 + delegType shift 58 + namesetType shift 59 + certType shift 60 + srvType shift 61 + regrType shift 62 + regtType shift 63 + infraType shift 64 + extraType shift 65 + nextType shift 66 + rBracket shift 74 + . error + + object goto 75 + name goto 39 + ip4 goto 41 + ip6 goto 40 + scion goto 42 + redir goto 43 + deleg goto 44 + nameset goto 45 + cert goto 46 + srv goto 47 + regr goto 48 + regt goto 49 + infra goto 50 + extra goto 51 + next goto 52 + +state 38 + objects: object. (35) + + . reduce 35 (src line 361) + + +state 39 + object: name. (37) + + . reduce 37 (src line 370) + + +state 40 + object: ip6. (38) + + . reduce 38 (src line 371) + + +state 41 + object: ip4. (39) + + . reduce 39 (src line 372) + + +state 42 + object: scion. (40) + + . reduce 40 (src line 373) + + +state 43 + object: redir. (41) + + . reduce 41 (src line 374) + + +state 44 + object: deleg. (42) + + . reduce 42 (src line 375) + + +state 45 + object: nameset. (43) + + . reduce 43 (src line 376) + + +state 46 + object: cert. (44) + + . reduce 44 (src line 377) + + +state 47 + object: srv. (45) + + . reduce 45 (src line 378) + + +state 48 + object: regr. (46) + + . reduce 46 (src line 379) + + +state 49 + object: regt. (47) + + . reduce 47 (src line 380) + + +state 50 + object: infra. (48) + + . reduce 48 (src line 381) + + +state 51 + object: extra. (49) + + . reduce 49 (src line 382) + + +state 52 + object: next. (50) + + . reduce 50 (src line 383) + + +state 53 + name: nameType.ID lBracket oTypes rBracket + + ID shift 76 + . error + + +state 54 + ip6: ip6Type.ID + + ID shift 77 + . error + + +state 55 + ip4: ip4Type.ID + + ID shift 78 + . error + + +state 56 + scion: scionType.ID + + ID shift 79 + . error + + +state 57 + redir: redirType.ID + + ID shift 80 + . error + + +state 58 + deleg: delegType.ed25519Type ID ID + + ed25519Type shift 81 + . error + + +state 59 + nameset: namesetType.freeText + + ID shift 83 + . error + + freeText goto 82 + +state 60 + cert: certType.protocolType certUsage hashType ID + + unspecified shift 85 + tls shift 86 + rhine shift 87 + . error + + protocolType goto 84 + +state 61 + srv: srvType.ID ID ID + + ID shift 88 + . error + + +state 62 + regr: regrType.freeText + + ID shift 83 + . error + + freeText goto 89 + +state 63 + regt: regtType.freeText + + ID shift 83 + . error + + freeText goto 90 + +state 64 + infra: infraType.ed25519Type ID ID + + ed25519Type shift 91 + . error + + +state 65 + extra: extraType.ed25519Type ID ID + + ed25519Type shift 92 + . error + + +state 66 + next: nextType.ed25519Type ID ID ID ID + + ed25519Type shift 93 + . error + + +state 67 + assertionBody: assertionType ID ID ID.lBracket objects rBracket + + lBracket shift 94 + . error + + +state 68 + shardBody: shardType ID ID shardRange.lBracket shardContent rBracket + + lBracket shift 95 + . error + + +state 69 + shardRange: ID.ID + shardRange: ID.rangeEnd + + ID shift 96 + rangeEnd shift 97 + . error + + +state 70 + shardRange: rangeBegin.ID + shardRange: rangeBegin.rangeEnd + + ID shift 98 + rangeEnd shift 99 + . error + + +state 71 + pshardBody: pshardType ID ID shardRange.bfAlgo bfHash ID + + bloomKM12 shift 101 + bloomKM16 shift 102 + bloomKM20 shift 103 + bloomKM24 shift 104 + . error + + bfAlgo goto 100 + +state 72 + zoneBody: zoneType ID ID lBracket.zoneContent rBracket + zoneContent: . (10) + + . reduce 10 (src line 228) + + zoneContent goto 105 + +state 73 + signatureMeta: sigType ed25519Type rains.ID ID ID + + ID shift 106 + . error + + +state 74 + assertionBody: assertionType ID lBracket objects rBracket. (33) + + . reduce 33 (src line 344) + + +state 75 + objects: objects object. (36) + + . reduce 36 (src line 365) + + +state 76 + name: nameType ID.lBracket oTypes rBracket + + lBracket shift 107 + . error + + +state 77 + ip6: ip6Type ID. (68) + + . reduce 68 (src line 461) + + +state 78 + ip4: ip4Type ID. (69) + + . reduce 69 (src line 472) + + +state 79 + scion: scionType ID. (70) + + . reduce 70 (src line 483) + + +state 80 + redir: redirType ID. (71) + + . reduce 71 (src line 494) + + +state 81 + deleg: delegType ed25519Type.ID ID + + ID shift 108 + . error + + +state 82 + nameset: namesetType freeText. (73) + freeText: freeText.ID + + ID shift 109 + . reduce 73 (src line 514) + + +state 83 + freeText: ID. (94) + + . reduce 94 (src line 658) + + +state 84 + cert: certType protocolType.certUsage hashType ID + + trustAnchor shift 111 + endEntity shift 112 + zoneAuth shift 113 + . error + + certUsage goto 110 + +state 85 + protocolType: unspecified. (81) + + . reduce 81 (src line 603) + + +state 86 + protocolType: tls. (82) + + . reduce 82 (src line 607) + + +state 87 + protocolType: rhine. (83) + + . reduce 83 (src line 611) + + +state 88 + srv: srvType ID.ID ID + + ID shift 114 + . error + + +state 89 + regr: regrType freeText. (76) + freeText: freeText.ID + + ID shift 109 + . reduce 76 (src line 546) + + +state 90 + regt: regtType freeText. (77) + freeText: freeText.ID + + ID shift 109 + . reduce 77 (src line 554) + + +state 91 + infra: infraType ed25519Type.ID ID + + ID shift 115 + . error + + +state 92 + extra: extraType ed25519Type.ID ID + + ID shift 116 + . error + + +state 93 + next: nextType ed25519Type.ID ID ID ID + + ID shift 117 + . error + + +state 94 + assertionBody: assertionType ID ID ID lBracket.objects rBracket + + nameType shift 53 + ip4Type shift 55 + ip6Type shift 54 + scionType shift 56 + redirType shift 57 + delegType shift 58 + namesetType shift 59 + certType shift 60 + srvType shift 61 + regrType shift 62 + regtType shift 63 + infraType shift 64 + extraType shift 65 + nextType shift 66 + . error + + objects goto 118 + object goto 38 + name goto 39 + ip4 goto 41 + ip6 goto 40 + scion goto 42 + redir goto 43 + deleg goto 44 + nameset goto 45 + cert goto 46 + srv goto 47 + regr goto 48 + regt goto 49 + infra goto 50 + extra goto 51 + next goto 52 + +state 95 + shardBody: shardType ID ID shardRange lBracket.shardContent rBracket + shardContent: . (19) + + . reduce 19 (src line 272) + + shardContent goto 119 + +state 96 + shardRange: ID ID. (15) + + . reduce 15 (src line 255) + + +state 97 + shardRange: ID rangeEnd. (17) + + . reduce 17 (src line 263) + + +state 98 + shardRange: rangeBegin ID. (16) + + . reduce 16 (src line 259) + + +state 99 + shardRange: rangeBegin rangeEnd. (18) + + . reduce 18 (src line 267) + + +state 100 + pshardBody: pshardType ID ID shardRange bfAlgo.bfHash ID + + shake256 shift 121 + fnv64 shift 122 + fnv128 shift 123 + . error + + bfHash goto 120 + +state 101 + bfAlgo: bloomKM12. (27) + + . reduce 27 (src line 320) + + +state 102 + bfAlgo: bloomKM16. (28) + + . reduce 28 (src line 324) + + +state 103 + bfAlgo: bloomKM20. (29) + + . reduce 29 (src line 328) + + +state 104 + bfAlgo: bloomKM24. (30) + + . reduce 30 (src line 332) + + +state 105 + zoneBody: zoneType ID ID lBracket zoneContent.rBracket + zoneContent: zoneContent.assertion + + assertionType shift 11 + rBracket shift 124 + . error + + assertion goto 125 + assertionBody goto 7 + +state 106 + signatureMeta: sigType ed25519Type rains ID.ID ID + + ID shift 126 + . error + + +state 107 + name: nameType ID lBracket.oTypes rBracket + + nameType shift 129 + ip4Type shift 130 + ip6Type shift 131 + scionType shift 132 + redirType shift 133 + delegType shift 134 + namesetType shift 135 + certType shift 136 + srvType shift 137 + regrType shift 138 + regtType shift 139 + infraType shift 140 + extraType shift 141 + nextType shift 142 + . error + + oTypes goto 127 + oType goto 128 + +state 108 + deleg: delegType ed25519Type ID.ID + + ID shift 143 + . error + + +state 109 + freeText: freeText ID. (95) + + . reduce 95 (src line 659) + + +state 110 + cert: certType protocolType certUsage.hashType ID + + noHash shift 145 + sha256 shift 146 + sha384 shift 147 + sha512 shift 148 + shake256 shift 149 + fnv64 shift 150 + fnv128 shift 151 + . error + + hashType goto 144 + +state 111 + certUsage: trustAnchor. (84) + + . reduce 84 (src line 616) + + +state 112 + certUsage: endEntity. (85) + + . reduce 85 (src line 620) + + +state 113 + certUsage: zoneAuth. (86) + + . reduce 86 (src line 624) + + +state 114 + srv: srvType ID ID.ID + + ID shift 152 + . error + + +state 115 + infra: infraType ed25519Type ID.ID + + ID shift 153 + . error + + +state 116 + extra: extraType ed25519Type ID.ID + + ID shift 154 + . error + + +state 117 + next: nextType ed25519Type ID.ID ID ID + + ID shift 155 + . error + + +state 118 + assertionBody: assertionType ID ID ID lBracket objects.rBracket + objects: objects.object + + nameType shift 53 + ip4Type shift 55 + ip6Type shift 54 + scionType shift 56 + redirType shift 57 + delegType shift 58 + namesetType shift 59 + certType shift 60 + srvType shift 61 + regrType shift 62 + regtType shift 63 + infraType shift 64 + extraType shift 65 + nextType shift 66 + rBracket shift 156 + . error + + object goto 75 + name goto 39 + ip4 goto 41 + ip6 goto 40 + scion goto 42 + redir goto 43 + deleg goto 44 + nameset goto 45 + cert goto 46 + srv goto 47 + regr goto 48 + regt goto 49 + infra goto 50 + extra goto 51 + next goto 52 + +state 119 + shardBody: shardType ID ID shardRange lBracket shardContent.rBracket + shardContent: shardContent.assertion + + assertionType shift 11 + rBracket shift 157 + . error + + assertion goto 158 + assertionBody goto 7 + +state 120 + pshardBody: pshardType ID ID shardRange bfAlgo bfHash.ID + + ID shift 159 + . error + + +state 121 + bfHash: shake256. (24) + + . reduce 24 (src line 307) + + +state 122 + bfHash: fnv64. (25) + + . reduce 25 (src line 311) + + +state 123 + bfHash: fnv128. (26) + + . reduce 26 (src line 315) + + +state 124 + zoneBody: zoneType ID ID lBracket zoneContent rBracket. (9) + + . reduce 9 (src line 219) + + +state 125 + zoneContent: zoneContent assertion. (11) + + . reduce 11 (src line 232) + + +state 126 + signatureMeta: sigType ed25519Type rains ID ID.ID + + ID shift 160 + . error + + +state 127 + name: nameType ID lBracket oTypes.rBracket + oTypes: oTypes.oType + + nameType shift 129 + ip4Type shift 130 + ip6Type shift 131 + scionType shift 132 + redirType shift 133 + delegType shift 134 + namesetType shift 135 + certType shift 136 + srvType shift 137 + regrType shift 138 + regtType shift 139 + infraType shift 140 + extraType shift 141 + nextType shift 142 + rBracket shift 161 + . error + + oType goto 162 + +state 128 + oTypes: oType. (52) + + . reduce 52 (src line 396) + + +state 129 + oType: nameType. (54) + + . reduce 54 (src line 405) + + +state 130 + oType: ip4Type. (55) + + . reduce 55 (src line 409) + + +state 131 + oType: ip6Type. (56) + + . reduce 56 (src line 413) + + +state 132 + oType: scionType. (57) + + . reduce 57 (src line 417) + + +state 133 + oType: redirType. (58) + + . reduce 58 (src line 421) + + +state 134 + oType: delegType. (59) + + . reduce 59 (src line 425) + + +state 135 + oType: namesetType. (60) + + . reduce 60 (src line 429) + + +state 136 + oType: certType. (61) + + . reduce 61 (src line 433) + + +state 137 + oType: srvType. (62) + + . reduce 62 (src line 437) + + +state 138 + oType: regrType. (63) + + . reduce 63 (src line 441) + + +state 139 + oType: regtType. (64) + + . reduce 64 (src line 445) + + +state 140 + oType: infraType. (65) + + . reduce 65 (src line 449) + + +state 141 + oType: extraType. (66) + + . reduce 66 (src line 453) + + +state 142 + oType: nextType. (67) + + . reduce 67 (src line 457) + + +state 143 + deleg: delegType ed25519Type ID ID. (72) + + . reduce 72 (src line 502) + + +state 144 + cert: certType protocolType certUsage hashType.ID + + ID shift 163 + . error + + +state 145 + hashType: noHash. (87) + + . reduce 87 (src line 629) + + +state 146 + hashType: sha256. (88) + + . reduce 88 (src line 633) + + +state 147 + hashType: sha384. (89) + + . reduce 89 (src line 637) + + +state 148 + hashType: sha512. (90) + + . reduce 90 (src line 641) + + +state 149 + hashType: shake256. (91) + + . reduce 91 (src line 645) + + +state 150 + hashType: fnv64. (92) + + . reduce 92 (src line 649) + + +state 151 + hashType: fnv128. (93) + + . reduce 93 (src line 653) + + +state 152 + srv: srvType ID ID ID. (75) + + . reduce 75 (src line 534) + + +state 153 + infra: infraType ed25519Type ID ID. (78) + + . reduce 78 (src line 562) + + +state 154 + extra: extraType ed25519Type ID ID. (79) + + . reduce 79 (src line 574) + + +state 155 + next: nextType ed25519Type ID ID.ID ID + + ID shift 164 + . error + + +state 156 + assertionBody: assertionType ID ID ID lBracket objects rBracket. (34) + + . reduce 34 (src line 351) + + +state 157 + shardBody: shardType ID ID shardRange lBracket shardContent rBracket. (14) + + . reduce 14 (src line 244) + + +state 158 + shardContent: shardContent assertion. (20) + + . reduce 20 (src line 276) + + +state 159 + pshardBody: pshardType ID ID shardRange bfAlgo bfHash ID. (23) + + . reduce 23 (src line 288) + + +state 160 + signatureMeta: sigType ed25519Type rains ID ID ID. (101) + + . reduce 101 (src line 689) + + +state 161 + name: nameType ID lBracket oTypes rBracket. (51) + + . reduce 51 (src line 385) + + +state 162 + oTypes: oTypes oType. (53) + + . reduce 53 (src line 400) + + +state 163 + cert: certType protocolType certUsage hashType ID. (74) + + . reduce 74 (src line 522) + + +state 164 + next: nextType ed25519Type ID ID ID.ID + + ID shift 165 + . error + + +state 165 + next: nextType ed25519Type ID ID ID ID. (80) + + . reduce 80 (src line 587) + + +48 terminals, 42 nonterminals +102 grammar rules, 166/16000 states +0 shift/reduce, 0 reduce/reduce conflicts reported +91 working sets used +memory: parser 84/240000 +15 extra closures +180 shift entries, 1 exceptions +54 goto entries +46 entries saved by goto default +Optimizer space used: output 211/240000 +211 table entries, 0 zero +maximum spread: 48, maximum offset: 127 diff --git a/internal/pkg/zonefile/zoneFileEncoder.go b/internal/pkg/zonefile/zoneFileEncoder.go index f00aaa16..e7d362f8 100644 --- a/internal/pkg/zonefile/zoneFileEncoder.go +++ b/internal/pkg/zonefile/zoneFileEncoder.go @@ -299,6 +299,8 @@ func encodeCertificate(cert object.Certificate) string { pt = TypeUnspecified case object.PTTLS: pt = TypePTTLS + case object.PTRhine: + pt = TypePTRhine default: log.Warn("Unsupported protocol type", "protocolType", cert.Type) return "" @@ -308,6 +310,9 @@ func encodeCertificate(cert object.Certificate) string { cu = TypeCUTrustAnchor case object.CUEndEntity: cu = TypeCUEndEntity + case object.CUZoneAuth: + cu = TypeCUZoneAuth + default: log.Warn("Unsupported certificate usage", "certUsage", cert.Usage) return "" diff --git a/internal/pkg/zonefile/zoneFileIO.go b/internal/pkg/zonefile/zoneFileIO.go index 77f99e3c..073c30d1 100644 --- a/internal/pkg/zonefile/zoneFileIO.go +++ b/internal/pkg/zonefile/zoneFileIO.go @@ -34,8 +34,10 @@ const ( TypeEd25519 = ":ed25519:" TypeUnspecified = ":unspecified:" TypePTTLS = ":tls:" + TypePTRhine = ":rhine:" TypeCUTrustAnchor = ":trustAnchor:" TypeCUEndEntity = ":endEntity:" + TypeCUZoneAuth = ":zoneAuth:" TypeNoHash = ":noHash:" TypeSha256 = ":sha256:" TypeSha384 = ":sha384:" diff --git a/internal/pkg/zonefile/zoneFileParser.go b/internal/pkg/zonefile/zoneFileParser.go index 217d8564..97ac607f 100644 --- a/internal/pkg/zonefile/zoneFileParser.go +++ b/internal/pkg/zonefile/zoneFileParser.go @@ -1,12 +1,12 @@ -// Code generated by goyacc -p ZFP -o internal/pkg/zonefile/zoneFileParser.go internal/pkg/zonefile/zoneFileParser.y. DO NOT EDIT. +// Code generated by goyacc -p ZFP -o zoneFileParser.go zoneFileParser.y. DO NOT EDIT. -//line internal/pkg/zonefile/zoneFileParser.y:5 +//line zoneFileParser.y:5 package zonefile import __yyfmt__ "fmt" -//line internal/pkg/zonefile/zoneFileParser.y:6 +//line zoneFileParser.y:6 import ( "bufio" @@ -111,7 +111,7 @@ func DecodeValidity(validSince, validUntil string) (int64, int64, error) { //Result gets stored in this variable var output []section.WithSigForward -//line internal/pkg/zonefile/zoneFileParser.y:116 +//line zoneFileParser.y:116 type ZFPSymType struct { yys int str string @@ -158,26 +158,28 @@ const sigType = 57365 const ed25519Type = 57366 const unspecified = 57367 const tls = 57368 -const trustAnchor = 57369 -const endEntity = 57370 -const noHash = 57371 -const sha256 = 57372 -const sha384 = 57373 -const sha512 = 57374 -const shake256 = 57375 -const fnv64 = 57376 -const fnv128 = 57377 -const bloomKM12 = 57378 -const bloomKM16 = 57379 -const bloomKM20 = 57380 -const bloomKM24 = 57381 -const rains = 57382 -const rangeBegin = 57383 -const rangeEnd = 57384 -const lBracket = 57385 -const rBracket = 57386 -const lParenthesis = 57387 -const rParenthesis = 57388 +const rhine = 57369 +const trustAnchor = 57370 +const endEntity = 57371 +const zoneAuth = 57372 +const noHash = 57373 +const sha256 = 57374 +const sha384 = 57375 +const sha512 = 57376 +const shake256 = 57377 +const fnv64 = 57378 +const fnv128 = 57379 +const bloomKM12 = 57380 +const bloomKM16 = 57381 +const bloomKM20 = 57382 +const bloomKM24 = 57383 +const rains = 57384 +const rangeBegin = 57385 +const rangeEnd = 57386 +const lBracket = 57387 +const rBracket = 57388 +const lParenthesis = 57389 +const rParenthesis = 57390 var ZFPToknames = [...]string{ "$end", @@ -206,8 +208,10 @@ var ZFPToknames = [...]string{ "ed25519Type", "unspecified", "tls", + "rhine", "trustAnchor", "endEntity", + "zoneAuth", "noHash", "sha256", "sha384", @@ -227,13 +231,14 @@ var ZFPToknames = [...]string{ "lParenthesis", "rParenthesis", } + var ZFPStatenames = [...]string{} const ZFPEofCode = 1 const ZFPErrCode = 2 const ZFPInitialStackSize = 16 -//line internal/pkg/zonefile/zoneFileParser.y:698 +//line zoneFileParser.y:706 /* Lexer */ // The parser expects the lexer to return 0 on EOF. @@ -312,10 +317,14 @@ func (l *ZFPLex) Lex(lval *ZFPSymType) int { return unspecified case TypePTTLS: return tls + case TypePTRhine: + return rhine case TypeCUTrustAnchor: return trustAnchor case TypeCUEndEntity: return endEntity + case TypeCUZoneAuth: + return zoneAuth case TypeNoHash: return noHash case TypeSha256: @@ -408,62 +417,62 @@ var ZFPExca = [...]int{ const ZFPPrivate = 57344 -const ZFPLast = 209 +const ZFPLast = 211 var ZFPAct = [...]int{ - - 126, 3, 37, 38, 82, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 53, + 128, 3, 37, 38, 82, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 53, 55, 54, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 16, 27, 106, 94, 93, 72, 73, - 159, 75, 110, 111, 11, 11, 29, 92, 97, 95, - 100, 101, 102, 103, 154, 69, 91, 33, 143, 144, - 145, 146, 147, 148, 149, 68, 25, 88, 89, 53, + 64, 65, 66, 16, 27, 107, 95, 94, 72, 73, + 93, 75, 161, 11, 11, 29, 92, 98, 96, 91, + 101, 102, 103, 104, 69, 81, 156, 36, 27, 33, + 145, 146, 147, 148, 149, 150, 151, 89, 90, 53, 55, 54, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 155, 122, 28, 98, 96, 119, 120, - 121, 34, 70, 85, 86, 90, 116, 71, 81, 36, - 27, 15, 163, 162, 74, 161, 123, 158, 157, 153, - 17, 18, 19, 11, 12, 13, 14, 152, 151, 156, - 75, 150, 1, 141, 124, 115, 160, 127, 128, 129, + 64, 65, 66, 68, 157, 124, 28, 99, 97, 121, + 122, 123, 25, 70, 111, 112, 113, 118, 85, 86, + 87, 15, 11, 12, 13, 14, 74, 125, 165, 164, + 17, 18, 19, 163, 160, 71, 159, 34, 155, 154, + 153, 158, 75, 152, 1, 143, 126, 117, 162, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 53, 55, 54, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 114, 113, 108, 112, 107, - 105, 83, 87, 80, 79, 78, 77, 76, 67, 35, - 32, 31, 30, 23, 22, 21, 20, 99, 118, 142, - 109, 84, 26, 24, 125, 52, 51, 50, 49, 48, - 47, 46, 45, 44, 43, 42, 40, 41, 39, 7, - 104, 117, 9, 5, 8, 4, 2, 10, 6, + 140, 141, 142, 53, 55, 54, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 116, 115, 109, + 114, 108, 106, 83, 88, 80, 79, 78, 77, 76, + 67, 35, 32, 31, 30, 23, 22, 21, 20, 100, + 120, 144, 110, 84, 26, 24, 127, 52, 51, 50, + 49, 48, 47, 46, 45, 44, 43, 42, 40, 41, + 39, 7, 105, 119, 9, 5, 8, 4, 2, 10, + 6, } -var ZFPPact = [...]int{ - -1000, -1000, 108, -1000, -1000, -1000, -1000, -12, -12, -12, - -12, 172, 171, 170, 169, -1000, 77, -1000, -1000, -1000, - 42, 168, 167, 166, 11, -1000, 165, 75, 132, 164, - 51, 51, -5, -1000, -1000, -1000, -1, 60, -1000, -1000, +var ZFPPact = [...]int{ + -1000, -1000, 97, -1000, -1000, -1000, -1000, -14, -14, -14, + -14, 174, 173, 172, 171, -1000, 35, -1000, -1000, -1000, + 41, 170, 169, 168, 11, -1000, 167, 33, 134, 166, + 50, 50, -7, -1000, -1000, -1000, -3, 60, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 163, 162, 161, 160, 159, 74, 157, - 68, 158, 157, 157, 71, 32, 23, -6, -7, 45, - 44, 14, -1000, 156, -1000, -1000, -8, -1000, -1000, -1000, - -1000, 155, 153, -1000, 15, -1000, -1000, 154, 153, 153, - 152, 151, 121, 132, -1000, -1000, -1000, -1000, -1000, 55, - -1000, -1000, -1000, -1000, 40, 120, 118, 119, -1000, 29, - -1000, -1000, 117, 114, 113, 105, 10, 39, 104, -1000, - -1000, -1000, -1000, -1000, 103, -4, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 165, 164, 163, 162, 161, 31, 159, + 73, 160, 159, 159, 25, 22, 16, -8, -9, 44, + 43, 12, -1000, 158, -1000, -1000, -10, -1000, -1000, -1000, + -1000, 157, 155, -1000, 66, -1000, -1000, -1000, 156, 155, + 155, 154, 153, 123, 134, -1000, -1000, -1000, -1000, -1000, + 54, -1000, -1000, -1000, -1000, 39, 122, 120, 121, -1000, + 29, -1000, -1000, -1000, 119, 116, 115, 114, 10, 38, + 112, -1000, -1000, -1000, -1000, -1000, 110, -4, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 101, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 99, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 98, -1000, + -1000, -1000, -1000, -1000, 109, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 105, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 104, -1000, } -var ZFPPgo = [...]int{ - 0, 208, 207, 206, 205, 204, 65, 203, 202, 201, - 200, 1, 199, 2, 3, 198, 197, 196, 195, 194, - 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, - 0, 101, 183, 66, 182, 4, 181, 180, 179, 178, - 177, 122, +var ZFPPgo = [...]int{ + 0, 210, 209, 208, 207, 206, 83, 205, 204, 203, + 202, 1, 201, 2, 3, 200, 199, 198, 197, 196, + 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, + 0, 101, 185, 92, 184, 4, 183, 182, 181, 180, + 179, 124, } -var ZFPR1 = [...]int{ +var ZFPR1 = [...]int{ 0, 41, 3, 3, 3, 3, 3, 1, 1, 2, 10, 10, 4, 4, 5, 6, 6, 6, 6, 9, 9, 7, 7, 8, 39, 39, 39, 40, 40, 40, @@ -472,11 +481,12 @@ var ZFPR1 = [...]int{ 14, 15, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 17, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 36, 36, 37, 37, 38, 38, 38, 38, 38, - 38, 38, 35, 35, 31, 32, 32, 33, 33, 34, + 28, 36, 36, 36, 37, 37, 37, 38, 38, 38, + 38, 38, 38, 38, 35, 35, 31, 32, 32, 33, + 33, 34, } -var ZFPR2 = [...]int{ +var ZFPR2 = [...]int{ 0, 1, 0, 2, 2, 2, 2, 1, 2, 6, 0, 2, 1, 2, 7, 2, 2, 2, 2, 0, 2, 1, 2, 7, 1, 1, 1, 1, 1, 1, @@ -486,60 +496,62 @@ var ZFPR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 2, 5, 4, 2, 2, 4, 4, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 3, 1, 2, 1, 2, 6, + 1, 1, 1, 1, 1, 2, 3, 1, 2, 1, + 2, 6, } -var ZFPChk = [...]int{ +var ZFPChk = [...]int{ -1000, -41, -3, -11, -4, -7, -1, -12, -5, -8, - -2, 5, 6, 7, 8, -31, 45, -31, -31, -31, - 4, 4, 4, 4, -32, -33, -34, 23, 43, 4, - 4, 4, 4, 46, -33, 4, 24, -13, -14, -15, + -2, 5, 6, 7, 8, -31, 47, -31, -31, -31, + 4, 4, 4, 4, -32, -33, -34, 23, 45, 4, + 4, 4, 4, 48, -33, 4, 24, -13, -14, -15, -17, -16, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, 9, 11, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 4, -6, 4, - 41, -6, 43, 40, 44, -14, 4, 4, 4, 4, - 4, 24, -35, 4, -36, 25, 26, 4, -35, -35, - 24, 24, 24, 43, 43, 4, 42, 4, 42, -40, - 36, 37, 38, 39, -10, 4, 43, 4, 4, -37, - 27, 28, 4, 4, 4, 4, -13, -9, -39, 33, - 34, 35, 44, -11, 4, -29, -30, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 4, -38, 29, 30, 31, 32, 33, 34, 35, - 4, 4, 4, 4, 44, 44, -11, 4, 4, 44, - -30, 4, 4, 4, + 43, -6, 45, 42, 46, -14, 4, 4, 4, 4, + 4, 24, -35, 4, -36, 25, 26, 27, 4, -35, + -35, 24, 24, 24, 45, 45, 4, 44, 4, 44, + -40, 38, 39, 40, 41, -10, 4, 45, 4, 4, + -37, 28, 29, 30, 4, 4, 4, 4, -13, -9, + -39, 35, 36, 37, 46, -11, 4, -29, -30, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 4, -38, 31, 32, 33, 34, 35, + 36, 37, 4, 4, 4, 4, 46, 46, -11, 4, + 4, 46, -30, 4, 4, 4, } -var ZFPDef = [...]int{ +var ZFPDef = [...]int{ 2, -2, 1, 3, 4, 5, 6, 31, 12, 21, 7, 0, 0, 0, 0, 32, 0, 13, 22, 8, - 0, 0, 0, 0, 0, 95, 97, 0, 0, 0, - 0, 0, 0, 94, 96, 98, 0, 0, 35, 37, + 0, 0, 0, 0, 0, 97, 99, 0, 0, 0, + 0, 0, 0, 96, 98, 100, 0, 0, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 33, 36, 0, 68, 69, 70, - 71, 0, 73, 92, 0, 81, 82, 0, 76, 77, - 0, 0, 0, 0, 19, 15, 17, 16, 18, 0, - 27, 28, 29, 30, 0, 0, 0, 0, 93, 0, - 83, 84, 0, 0, 0, 0, 0, 0, 0, 24, - 25, 26, 9, 11, 0, 0, 52, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 72, 0, 85, 86, 87, 88, 89, 90, 91, - 75, 78, 79, 0, 34, 14, 20, 23, 99, 51, - 53, 74, 0, 80, + 71, 0, 73, 94, 0, 81, 82, 83, 0, 76, + 77, 0, 0, 0, 0, 19, 15, 17, 16, 18, + 0, 27, 28, 29, 30, 0, 0, 0, 0, 95, + 0, 84, 85, 86, 0, 0, 0, 0, 0, 0, + 0, 24, 25, 26, 9, 11, 0, 0, 52, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 72, 0, 87, 88, 89, 90, 91, + 92, 93, 75, 78, 79, 0, 34, 14, 20, 23, + 101, 51, 53, 74, 0, 80, } -var ZFPTok1 = [...]int{ +var ZFPTok1 = [...]int{ 1, } -var ZFPTok2 = [...]int{ +var ZFPTok2 = [...]int{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, + 42, 43, 44, 45, 46, 47, 48, } + var ZFPTok3 = [...]int{ 0, } @@ -883,50 +895,50 @@ ZFPdefault: case 1: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:187 +//line zoneFileParser.y:187 { output = ZFPDollar[1].sections } case 2: ZFPDollar = ZFPS[ZFPpt-0 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:192 +//line zoneFileParser.y:192 { ZFPVAL.sections = nil } case 3: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:196 +//line zoneFileParser.y:196 { ZFPVAL.sections = append(ZFPDollar[1].sections, ZFPDollar[2].assertion) } case 4: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:200 +//line zoneFileParser.y:200 { ZFPVAL.sections = append(ZFPDollar[1].sections, ZFPDollar[2].shard) } case 5: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:204 +//line zoneFileParser.y:204 { ZFPVAL.sections = append(ZFPDollar[1].sections, ZFPDollar[2].pshard) } case 6: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:208 +//line zoneFileParser.y:208 { ZFPVAL.sections = append(ZFPDollar[1].sections, ZFPDollar[2].zone) } case 8: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:214 +//line zoneFileParser.y:214 { AddSigs(ZFPDollar[1].zone, ZFPDollar[2].signatures) ZFPVAL.zone = ZFPDollar[1].zone } case 9: ZFPDollar = ZFPS[ZFPpt-6 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:220 +//line zoneFileParser.y:220 { ZFPVAL.zone = §ion.Zone{ SubjectZone: ZFPDollar[2].str, @@ -936,26 +948,26 @@ ZFPdefault: } case 10: ZFPDollar = ZFPS[ZFPpt-0 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:229 +//line zoneFileParser.y:229 { ZFPVAL.assertions = nil } case 11: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:233 +//line zoneFileParser.y:233 { ZFPVAL.assertions = append(ZFPDollar[1].assertions, ZFPDollar[2].assertion) } case 13: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:239 +//line zoneFileParser.y:239 { AddSigs(ZFPDollar[1].shard, ZFPDollar[2].signatures) ZFPVAL.shard = ZFPDollar[1].shard } case 14: ZFPDollar = ZFPS[ZFPpt-7 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:245 +//line zoneFileParser.y:245 { ZFPVAL.shard = §ion.Shard{ SubjectZone: ZFPDollar[2].str, @@ -967,50 +979,50 @@ ZFPdefault: } case 15: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:256 +//line zoneFileParser.y:256 { ZFPVAL.shardRange = []string{ZFPDollar[1].str, ZFPDollar[2].str} } case 16: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:260 +//line zoneFileParser.y:260 { ZFPVAL.shardRange = []string{"<", ZFPDollar[2].str} } case 17: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:264 +//line zoneFileParser.y:264 { ZFPVAL.shardRange = []string{ZFPDollar[1].str, ">"} } case 18: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:268 +//line zoneFileParser.y:268 { ZFPVAL.shardRange = []string{"<", ">"} } case 19: ZFPDollar = ZFPS[ZFPpt-0 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:273 +//line zoneFileParser.y:273 { ZFPVAL.assertions = nil } case 20: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:277 +//line zoneFileParser.y:277 { ZFPVAL.assertions = append(ZFPDollar[1].assertions, ZFPDollar[2].assertion) } case 22: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:283 +//line zoneFileParser.y:283 { AddSigs(ZFPDollar[1].pshard, ZFPDollar[2].signatures) ZFPVAL.pshard = ZFPDollar[1].pshard } case 23: ZFPDollar = ZFPS[ZFPpt-7 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:289 +//line zoneFileParser.y:289 { decodedFilter, err := hex.DecodeString(ZFPDollar[7].str) if err != nil { @@ -1030,56 +1042,56 @@ ZFPdefault: } case 24: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:308 +//line zoneFileParser.y:308 { ZFPVAL.hashType = algorithmTypes.Shake256 } case 25: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:312 +//line zoneFileParser.y:312 { ZFPVAL.hashType = algorithmTypes.Fnv64 } case 26: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:316 +//line zoneFileParser.y:316 { ZFPVAL.hashType = algorithmTypes.Fnv128 } case 27: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:321 +//line zoneFileParser.y:321 { ZFPVAL.bfAlgo = section.BloomKM12 } case 28: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:325 +//line zoneFileParser.y:325 { ZFPVAL.bfAlgo = section.BloomKM16 } case 29: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:329 +//line zoneFileParser.y:329 { ZFPVAL.bfAlgo = section.BloomKM20 } case 30: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:333 +//line zoneFileParser.y:333 { ZFPVAL.bfAlgo = section.BloomKM24 } case 32: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:339 +//line zoneFileParser.y:339 { AddSigs(ZFPDollar[1].assertion, ZFPDollar[2].signatures) ZFPVAL.assertion = ZFPDollar[1].assertion } case 33: ZFPDollar = ZFPS[ZFPpt-5 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:345 +//line zoneFileParser.y:345 { ZFPVAL.assertion = §ion.Assertion{ SubjectName: ZFPDollar[2].str, @@ -1088,7 +1100,7 @@ ZFPdefault: } case 34: ZFPDollar = ZFPS[ZFPpt-7 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:352 +//line zoneFileParser.y:352 { ZFPVAL.assertion = §ion.Assertion{ SubjectName: ZFPDollar[2].str, @@ -1099,19 +1111,19 @@ ZFPdefault: } case 35: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:362 +//line zoneFileParser.y:362 { ZFPVAL.objects = []object.Object{ZFPDollar[1].object} } case 36: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:366 +//line zoneFileParser.y:366 { ZFPVAL.objects = append(ZFPDollar[1].objects, ZFPDollar[2].object) } case 51: ZFPDollar = ZFPS[ZFPpt-5 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:386 +//line zoneFileParser.y:386 { ZFPVAL.object = object.Object{ Type: object.OTName, @@ -1123,103 +1135,103 @@ ZFPdefault: } case 52: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:397 +//line zoneFileParser.y:397 { ZFPVAL.objectTypes = []object.Type{ZFPDollar[1].objectType} } case 53: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:401 +//line zoneFileParser.y:401 { ZFPVAL.objectTypes = append(ZFPDollar[1].objectTypes, ZFPDollar[2].objectType) } case 54: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:406 +//line zoneFileParser.y:406 { ZFPVAL.objectType = object.OTName } case 55: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:410 +//line zoneFileParser.y:410 { ZFPVAL.objectType = object.OTIP4Addr } case 56: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:414 +//line zoneFileParser.y:414 { ZFPVAL.objectType = object.OTIP6Addr } case 57: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:418 +//line zoneFileParser.y:418 { ZFPVAL.objectType = object.OTScionAddr } case 58: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:422 +//line zoneFileParser.y:422 { ZFPVAL.objectType = object.OTRedirection } case 59: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:426 +//line zoneFileParser.y:426 { ZFPVAL.objectType = object.OTDelegation } case 60: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:430 +//line zoneFileParser.y:430 { ZFPVAL.objectType = object.OTNameset } case 61: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:434 +//line zoneFileParser.y:434 { ZFPVAL.objectType = object.OTCertInfo } case 62: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:438 +//line zoneFileParser.y:438 { ZFPVAL.objectType = object.OTServiceInfo } case 63: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:442 +//line zoneFileParser.y:442 { ZFPVAL.objectType = object.OTRegistrar } case 64: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:446 +//line zoneFileParser.y:446 { ZFPVAL.objectType = object.OTRegistrant } case 65: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:450 +//line zoneFileParser.y:450 { ZFPVAL.objectType = object.OTInfraKey } case 66: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:454 +//line zoneFileParser.y:454 { ZFPVAL.objectType = object.OTExtraKey } case 67: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:458 +//line zoneFileParser.y:458 { ZFPVAL.objectType = object.OTNextKey } case 68: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:462 +//line zoneFileParser.y:462 { ip := net.ParseIP(ZFPDollar[2].str) if ip == nil { @@ -1232,7 +1244,7 @@ ZFPdefault: } case 69: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:473 +//line zoneFileParser.y:473 { ip := net.ParseIP(ZFPDollar[2].str) if ip == nil { @@ -1245,7 +1257,7 @@ ZFPdefault: } case 70: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:484 +//line zoneFileParser.y:484 { addr, err := object.ParseSCIONAddress(ZFPDollar[2].str) if err != nil { @@ -1258,7 +1270,7 @@ ZFPdefault: } case 71: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:495 +//line zoneFileParser.y:495 { ZFPVAL.object = object.Object{ Type: object.OTRedirection, @@ -1267,7 +1279,7 @@ ZFPdefault: } case 72: ZFPDollar = ZFPS[ZFPpt-4 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:503 +//line zoneFileParser.y:503 { pkey, err := DecodeEd25519PublicKeyData(ZFPDollar[4].str, ZFPDollar[3].str) if err != nil { @@ -1280,7 +1292,7 @@ ZFPdefault: } case 73: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:515 +//line zoneFileParser.y:515 { ZFPVAL.object = object.Object{ Type: object.OTNameset, @@ -1289,7 +1301,7 @@ ZFPdefault: } case 74: ZFPDollar = ZFPS[ZFPpt-5 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:523 +//line zoneFileParser.y:523 { cert, err := DecodeCertificate(ZFPDollar[2].protocolType, ZFPDollar[3].certUsage, ZFPDollar[4].hashType, ZFPDollar[5].str) if err != nil { @@ -1302,7 +1314,7 @@ ZFPdefault: } case 75: ZFPDollar = ZFPS[ZFPpt-4 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:535 +//line zoneFileParser.y:535 { srv, err := DecodeSrv(ZFPDollar[2].str, ZFPDollar[3].str, ZFPDollar[4].str) if err != nil { @@ -1315,7 +1327,7 @@ ZFPdefault: } case 76: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:547 +//line zoneFileParser.y:547 { ZFPVAL.object = object.Object{ Type: object.OTRegistrar, @@ -1324,7 +1336,7 @@ ZFPdefault: } case 77: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:555 +//line zoneFileParser.y:555 { ZFPVAL.object = object.Object{ Type: object.OTRegistrant, @@ -1333,7 +1345,7 @@ ZFPdefault: } case 78: ZFPDollar = ZFPS[ZFPpt-4 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:563 +//line zoneFileParser.y:563 { pkey, err := DecodeEd25519PublicKeyData(ZFPDollar[4].str, ZFPDollar[3].str) if err != nil { @@ -1346,7 +1358,7 @@ ZFPdefault: } case 79: ZFPDollar = ZFPS[ZFPpt-4 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:575 +//line zoneFileParser.y:575 { //TODO CFE as of now there is only the rains key space. There will //be additional rules in case there are new key spaces pkey, err := DecodeEd25519PublicKeyData(ZFPDollar[4].str, ZFPDollar[3].str) @@ -1360,7 +1372,7 @@ ZFPdefault: } case 80: ZFPDollar = ZFPS[ZFPpt-6 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:588 +//line zoneFileParser.y:588 { pkey, err := DecodeEd25519PublicKeyData(ZFPDollar[4].str, ZFPDollar[3].str) if err != nil { @@ -1377,97 +1389,109 @@ ZFPdefault: } case 81: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:604 +//line zoneFileParser.y:604 { ZFPVAL.protocolType = object.PTUnspecified } case 82: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:608 +//line zoneFileParser.y:608 { ZFPVAL.protocolType = object.PTTLS } case 83: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:613 +//line zoneFileParser.y:612 { - ZFPVAL.certUsage = object.CUTrustAnchor + ZFPVAL.protocolType = object.PTRhine } case 84: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:617 +//line zoneFileParser.y:617 { - ZFPVAL.certUsage = object.CUEndEntity + ZFPVAL.certUsage = object.CUTrustAnchor } case 85: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:622 +//line zoneFileParser.y:621 { - ZFPVAL.hashType = algorithmTypes.NoHashAlgo + ZFPVAL.certUsage = object.CUEndEntity } case 86: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:626 +//line zoneFileParser.y:625 { - ZFPVAL.hashType = algorithmTypes.Sha256 + ZFPVAL.certUsage = object.CUZoneAuth } case 87: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:630 +//line zoneFileParser.y:630 { - ZFPVAL.hashType = algorithmTypes.Sha384 + ZFPVAL.hashType = algorithmTypes.NoHashAlgo } case 88: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:634 +//line zoneFileParser.y:634 { - ZFPVAL.hashType = algorithmTypes.Sha512 + ZFPVAL.hashType = algorithmTypes.Sha256 } case 89: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:638 +//line zoneFileParser.y:638 { - ZFPVAL.hashType = algorithmTypes.Shake256 + ZFPVAL.hashType = algorithmTypes.Sha384 } case 90: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:642 +//line zoneFileParser.y:642 { - ZFPVAL.hashType = algorithmTypes.Fnv64 + ZFPVAL.hashType = algorithmTypes.Sha512 } case 91: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:646 +//line zoneFileParser.y:646 { - ZFPVAL.hashType = algorithmTypes.Fnv128 + ZFPVAL.hashType = algorithmTypes.Shake256 + } + case 92: + ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] +//line zoneFileParser.y:650 + { + ZFPVAL.hashType = algorithmTypes.Fnv64 } case 93: + ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] +//line zoneFileParser.y:654 + { + ZFPVAL.hashType = algorithmTypes.Fnv128 + } + case 95: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:652 +//line zoneFileParser.y:660 { ZFPVAL.str = ZFPDollar[1].str + " " + ZFPDollar[2].str } - case 94: + case 96: ZFPDollar = ZFPS[ZFPpt-3 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:657 +//line zoneFileParser.y:665 { ZFPVAL.signatures = ZFPDollar[2].signatures } - case 95: + case 97: ZFPDollar = ZFPS[ZFPpt-1 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:662 +//line zoneFileParser.y:670 { ZFPVAL.signatures = []signature.Sig{ZFPDollar[1].signature} } - case 96: + case 98: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:666 +//line zoneFileParser.y:674 { ZFPVAL.signatures = append(ZFPDollar[1].signatures, ZFPDollar[2].signature) } - case 98: + case 100: ZFPDollar = ZFPS[ZFPpt-2 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:672 +//line zoneFileParser.y:680 { sigData, err := hex.DecodeString(ZFPDollar[2].str) if err != nil { @@ -1476,9 +1500,9 @@ ZFPdefault: ZFPDollar[1].signature.Data = sigData ZFPVAL.signature = ZFPDollar[1].signature } - case 99: + case 101: ZFPDollar = ZFPS[ZFPpt-6 : ZFPpt+1] -//line internal/pkg/zonefile/zoneFileParser.y:682 +//line zoneFileParser.y:690 { publicKeyID, err := DecodePublicKeyID(ZFPDollar[4].str) if err != nil { diff --git a/internal/pkg/zonefile/zoneFileParser.y b/internal/pkg/zonefile/zoneFileParser.y index 8064b0ff..0e521992 100644 --- a/internal/pkg/zonefile/zoneFileParser.y +++ b/internal/pkg/zonefile/zoneFileParser.y @@ -169,7 +169,7 @@ var output []section.WithSigForward // Signature algorithm types %token ed25519Type // Certificate types -%token unspecified tls trustAnchor endEntity +%token unspecified tls rhine trustAnchor endEntity zoneAuth // Hash algorithm types %token noHash sha256 sha384 sha512 shake256 fnv64 fnv128 // Bloom filter algorithm @@ -608,6 +608,10 @@ protocolType : unspecified { $$ = object.PTTLS } + | rhine + { + $$ = object.PTRhine + } certUsage : trustAnchor { @@ -617,6 +621,10 @@ certUsage : trustAnchor { $$ = object.CUEndEntity } + | zoneAuth + { + $$ = object.CUZoneAuth + } hashType : noHash { @@ -773,10 +781,14 @@ func (l *ZFPLex) Lex(lval *ZFPSymType) int { return unspecified case TypePTTLS : return tls + case TypePTRhine : + return rhine case TypeCUTrustAnchor : return trustAnchor case TypeCUEndEntity : return endEntity + case TypeCUZoneAuth: + return zoneAuth case TypeNoHash : return noHash case TypeSha256 : diff --git a/offlineauth/Makefile b/offlineauth/Makefile new file mode 100644 index 00000000..0b3ebc77 --- /dev/null +++ b/offlineauth/Makefile @@ -0,0 +1,29 @@ +BUILD_PATH=${PWD}/build/ + +all: clean child parent ca checker keymanager + +clean: + rm -rf ${BUILD_PATH} + mkdir ${BUILD_PATH} + +child: + go build -o ${BUILD_PATH}child cmd/child/run_child.go + +parent: + go build -o ${BUILD_PATH}parent cmd/parent/run_parent.go + +ca: + go build -o ${BUILD_PATH}ca cmd/ca/run_ca.go + +checker: + go build -o ${BUILD_PATH}checker cmd/checkerExtension/run_checker.go + +keymanager: + go build -o ${BUILD_PATH}keyGen cmd/keyManager/keyGen.go + go build -o ${BUILD_PATH}certGen cmd/keyManager/certGen.go + + +test: + go test -v test/rainsdeleg_test.go -run TestFull + +.PHONY: all clean child parent ca checker keymanager test \ No newline at end of file diff --git a/offlineauth/README.md b/offlineauth/README.md new file mode 100644 index 00000000..9efe1566 --- /dev/null +++ b/offlineauth/README.md @@ -0,0 +1,184 @@ + # Prototype Implementation of RAINS Offline Authentication Protocol. + +**Code in cyrill-k/trustflex directory is copied from https://github.com/cyrill-k/trustflex** + +**Some Code in common/logclient.go is copied from https://github.com/cyrill-k/trustflex/trillian/tmain/main.go** + +**Code to handle configs is copied from https://github.com/netsec-ethz/rains** + +## Dependencies: +Two packages need to be replaced, change + +```replace github.com/google/trillian => /home/burki/go/src/github.com/cyrill-k/trillian``` + +```replace github.com/miekg/dns => /home/burki/go/src/github.com/robinburkhard/dns``` + +to your path in `go.mod` + +Clone the repos from here: + +trillian: `github.com/cyrill-k/trillian` + +miekg/dns: `github.com/robinburkhard/dns` + +## System Components: + - Child: Command line program for child zone authorities to renew their certificates. Sends ReNewDlg and KeyChangeDlg requests to a CA and adds them to the log. + - Parent: Command line program for a parent zone authority to obtain a certificate for a child zone. Parent creates NewDlg Requests using a CSR from one of its child zones and sends them to a CA. It also adds obtained Certificates to the log server. + - CA: Server receiving NewDlg requests from a parent zone and ReNewDlg/KeyChangeDlg requests from a child zone. It contacts the log-server to check for existing certificates. + - CheckerExtension: Checker Extension is the interface for parent and child zones to add certificates to the log. The log server must only accept new certificates from the checker extension. + +## How to run + +### trustflex-docker +trustflex-docker is a container cluster for the log server components. Rainsdeleg uses the map-server to receive information on existing certificates and the log-server to add certificates. +Repo can be found here: ``github.com/cyrill-k/trustflex-docker`` + +Make sure to add ``EXPOSE 8090`` and ``EXPOSE 8094`` to ``Go/Dockerfile`` so that the map-server and log-server can be accessed. Later the checkerExtension should be a container itself and the log-server should no longer be accessible from the outside. (dont expose 8090) + +Run `docker-compose up` to start the log server components + +Access the container: ``docker exec -i -t experiment bash`` + +Check out the `makefile` in `cyrill-k/trustflex` for log server administration. +Before using it for rainsdeleg run +`make createmap` and `make createtree` and `make map_initial` + +Update configs of rainsdeleg systems with `logid1 mapid1 logpk1.pem mapk1.pem`. They can be found in +the confing folder of the trustflex-docker repo or in `/mnt/config/` in the container. + +### Makefile + +run ``make all`` to create `ca` `checker` `parent` `child` `keyGen` `certGen` binaries in `/build`. + +### CA and CheckerExtension + +Run `./ca [ConfigPath]` and `./checker [ConfigPath]`. +Example configs can be found in `testing/testdata/configs/` + +More information about the components and their config can be found in `ca/README.md` and `checkerExtension/README.md` + +### Parent Zone Manager + +Handles NewDlg requests for a given CSR \ +`./parent [ParentConfigPath] --NewDlg PathToCSR` + +### Child Zone Manager +Handles Creating CSRs for NewDlg or ReNewDlg and KeyChangeDlg requests \ +`./child NewDlg [KeyType] [PathToPrivateKey] --zone DNSZone`\ +`./child ReNewDlg [KeyType] [PathToPrivateKey] [PathToCertificate]` + + +### KeyGen + +Use `./keyGen.go` and `./certGen.go` to generate keys and self signed CA certificates for testing +### Examples + +Run CA and Checker: +``` +cd testing +../build/ca testdata/configs/caconfig.conf +../build/checker testdata/configs/checkerconfig.conf +``` +Create NewDlg Request for `ethz.ch` using parent for zone for `ch` +``` +../buld/child NewDlg Ed25519 testdata/keys/ethz.ch_Key.pem --out example/ --zone ethz.ch +../build/parent testdata/configs/ch_parentconfig.conf --NewDlg example/eth.ch_csr.pem +``` + + +### Run Tests + +`make test` + +trustflex-docker needs to be running. Test configs are set to log-server address `172.18.0.3` and +map-server address `172.18.0.5`. + +Check your container addresses: \ +`docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' map-server` \ +`docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' log-server` + + +## Setup step by step (toy example) + +### Step 1: setup repo and dependencies + +clone `github.com/cyrill-k/trillian` and `github.com/robinburkhard/dns` into your `/home/user/go/src/github.com/` folder. + +Change paths to replace in `go.mod` + + +### Step 2: setup F-PKI environment + +clone ``github.com/cyrill-k/trustflex-docker`` + +add ``EXPOSE 8090`` and ``EXPOSE 8094`` to ``Go/Dockerfile`` + +Run `docker-compose up` in repo folder to start + +Access the container: ``docker exec -i -t experiment bash`` and run `mkdir data` and `make createmap` and `make createtree` and `make map_initial` + +read out `logid1 mapid1 logpk1.pem mapk1.pem` in `/mnt/config/` + +### optional step for testing with go tests: update and create configs for your F-PKI setup + +change at least: + +```go +MAP_PK_PATH = "testdata/mappk1.pem" +LOG_PK_PATH = "testdata/logpk1.pem" +MAP_ID = 3213023363744691885 +LOG_ID = 8493809986858120401 +``` + +in `offlineAuth/test/rainsdeleg_test.go` to fit your f-pki setup. + +Then run the `TestCreateDemoFiles` function in to create necessary configs for to run a manual toy example. Alternatively use `TestFull` function to test automatically. + +### Step 3: run toy example with demo files + +run `make` to create the binaries in `/build` + + +change `testdata/logpk1.pem` and `testdata/mapk1.pem` to match your f-pki setup + +change `LogID` and `MapID` values in `demo/checker.conf` and `demo/ca.conf` to match your f-pki setup + +run ca: + +``cd test `` + +``../build/ca demo/ca.conf`` + + +run checker: + + ``cd test `` + + ``../build/checker demo/checker.conf `` + + +child generate key and csr: + + ``../build/keyGen Ed25519 demo/ethz.ch.rains.key `` + + ``../build/child NewDlg Ed25519 demo/ethz.ch.rains.key --zone ethz.ch.rains --out demo `` + +parse: +``openssl req -text -noout -in demo/ethz.ch.rains_Csr.pem`` + + +parent run newdlg : + + + `` ../build/parent demo/ch.conf --NewDlg demo/ethz.ch.rains_Csr.pem `` + +parse: + + ``openssl x509 -text -noout -in demo/ch.cert `` + + ``openssl x509 -text -noout -in demo/ethz.ch.rains_Cert.pem `` + + + + + diff --git a/offlineauth/build/ca b/offlineauth/build/ca new file mode 100755 index 00000000..e4a771a4 Binary files /dev/null and b/offlineauth/build/ca differ diff --git a/offlineauth/build/certGen b/offlineauth/build/certGen new file mode 100755 index 00000000..1f17afbb Binary files /dev/null and b/offlineauth/build/certGen differ diff --git a/offlineauth/build/checker b/offlineauth/build/checker new file mode 100755 index 00000000..0035c23b Binary files /dev/null and b/offlineauth/build/checker differ diff --git a/offlineauth/build/child b/offlineauth/build/child new file mode 100755 index 00000000..b5dbaf3f Binary files /dev/null and b/offlineauth/build/child differ diff --git a/offlineauth/build/keyGen b/offlineauth/build/keyGen new file mode 100755 index 00000000..d0369096 Binary files /dev/null and b/offlineauth/build/keyGen differ diff --git a/offlineauth/build/parent b/offlineauth/build/parent new file mode 100755 index 00000000..02bd3307 Binary files /dev/null and b/offlineauth/build/parent differ diff --git a/offlineauth/ca/README.md b/offlineauth/ca/README.md new file mode 100644 index 00000000..5df2e9c9 --- /dev/null +++ b/offlineauth/ca/README.md @@ -0,0 +1,18 @@ +# CA Server + +`go run run_ca.go [ConfigPath]` + +## Config: + +``` +{ + "PrivateKeyAlgorithm": "RSA", + "PrivateKeyPath": "data/privkey.pem", + "CertificatePath": "data/cacert.pem", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "data/mappk1.pem", + "MapId": 5250323035397941290, + "ServerAddress" : "localhost:10000", // Address of CA + "RootCertsPath" : "roots/" // Certificates in this directory are added to the Cert Pool +} +``` \ No newline at end of file diff --git a/offlineauth/ca/ca.go b/offlineauth/ca/ca.go new file mode 100644 index 00000000..df26ff84 --- /dev/null +++ b/offlineauth/ca/ca.go @@ -0,0 +1,740 @@ +package ca + +import ( + "crypto" + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + logger15 "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/rainsclientlog" + "github.com/robinburkhard/rainsdeleg/requests" + "io/ioutil" + "log" + "math/big" + "net/http" + "strings" + "time" +) + +var logger = logger15.New("Module", "CA") +// var loggerNewDlg = logger.New("Request", "NewDlg") //TODO make logger for every request + + +type CA interface { // TODO implement interface + ProcessNewDlgRequest(preq requests.NewDlgRequest) ([]byte, bool, *CAError) + IssueCertificate(csr *x509.CertificateRequest) ([]byte, error) +} + +type Ca struct { + Address string + PublicKey crypto.PublicKey + PrivateKey crypto.PrivateKey + CACertificate *x509.Certificate + MapServerAddr string + MapServerPkeyPath string + mapID int64 + CertPool *x509.CertPool + +} + +type CAError struct { + Code int + Err error +} + +func (e *CAError) Error() string { + return fmt.Sprintf("code: %s, err: %s", e.Code, e.Err) +} + +func LoadConfig(Path string) (Config, error) { + conf := Config{} + file, err := ioutil.ReadFile(Path) + if err != nil { + return Config{}, err + } + if err = json.Unmarshal(file, &conf); err != nil { + return Config{}, err + } + + return conf, nil +} + +func NewCA(config Config) *Ca { + if config.PrivateKeyAlgorithm == "" { + log.Fatal("No private key alg in config") + } + var privKey interface{} + var pubkey interface{} + var cert *x509.Certificate + + if config.PrivateKeyPath == "" { + switch config.PrivateKeyAlgorithm { + case "RSA": + privKey, _ = rsa.GenerateKey(rand.Reader, 2048) + pubkey = privKey.(*rsa.PrivateKey).Public() + case "Ed25519": + pubkey, privKey, _ = ed25519.GenerateKey(rand.Reader) + } + } else { + switch config.PrivateKeyAlgorithm { + case "RSA": + var err error + privKey, err = common.LoadRSAPrivateKeyPEM(config.PrivateKeyPath) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + pubkey = privKey.(*rsa.PrivateKey).Public() + case "Ed25519": + var err error + privKey, err = common.LoadPrivateKeyEd25519(config.PrivateKeyPath) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + pubkey = privKey.(ed25519.PrivateKey).Public() + } + } + + if config.CertificatePath == "" { + certbytes, _ := common.CreateSelfSignedCertCA(pubkey, interface{}(privKey)) + cert, _ = x509.ParseCertificate(certbytes) + } else { + var err error + cert, err = common.LoadCertificatePEM(config.CertificatePath) + if err != nil { + log.Fatal("Error loading certificate: ", err) + } + } + + var CaCertPool *x509.CertPool + CaCertPool, err := x509.SystemCertPool() + if err == nil { + CaCertPool = x509.NewCertPool() + } + myca := Ca{ + PublicKey: pubkey, + PrivateKey: privKey, + CACertificate: cert, + MapServerAddr: config.MapServerAddress, + MapServerPkeyPath: config.MapServerPublicKeyPath, + mapID: config.MapId, + CertPool: CaCertPool, + Address: config.ServerAddress, + } + + files, err := ioutil.ReadDir(config.RootCertsPath) + if err != nil { + log.Fatal("Error reading roots directory: ", err) + } + + for _, file := range files { + pemfile, _ := ioutil.ReadFile(config.RootCertsPath + file.Name()) + if myca.CertPool.AppendCertsFromPEM(pemfile) { + logger.Warn("Added " + file.Name()+ " to trust root") + } + } + + + return &myca + +} + +func (myca *Ca) ProcessNewDlgRequest(preq requests.NewDlgRequest) ([]byte, *CAError) { + logger.Info("CA: Processing NewDlg Request") + csrbytes, err := common.DecodeBase64(preq.Payload.Csr) + if err != nil { + return nil, &CAError{ + Code: requests.CsrDecodeError, + Err: err, + } + } + csr, err := x509.ParseCertificateRequest(csrbytes) + if err != nil { + return nil, &CAError{ + Code: requests.CsrParseError, + Err: err, + } + } + if err := csr.CheckSignature(); err != nil { + return nil, &CAError{ + Code: requests.CsrSignatureInvalid, + Err: err, + } + } + var childzone string + if len(csr.DNSNames) > 0 { + childzone = csr.DNSNames[0] + } else { + return nil, &CAError{ + Code: requests.CsrSANDNSMissing, + Err: errors.New(requests.ErrorMsg[requests.CsrSANDNSMissing]), + } + } + + logger.Info("Parsed CSR", "zone", childzone) + + parentzone := common.GetParentZone(childzone) + var publicKey interface{} + + // parent authentication + switch preq.Header.Parent_auth_type { + + case "NOAUTH": + // TODO REMOVE + // only for testing + logger.Crit("NO PARENT AUTHENTICATION TYPE (TESTING)") + publicKey, _ = common.DecodePublicKey(preq.Header.Pubkey, preq.Header.Alg) + + case "dnssec": + logger.Info("CA: Authenticating Parent: DNSSEC") + var err error + switch preq.Header.Alg { + case "RSA": + publicKey, err = common.QueryDNSKeyRSA(parentzone) + case "Ed25519": + publicKey, err = common.QueryDNSKeyEd25519(parentzone) + } + if err != nil { + return nil, &CAError{ + Code: requests.ParentAuthDNSSECFailed, + Err: err, + } + } + logger.Info("CA: Authenticated Parent DNSSEC") + + + case "certificate": + logger.Info("CA: Authenticating Parent: Certificate") + certbytes, err := common.DecodeBase64(preq.Header.Parent_cert) + if err != nil { + return nil, &CAError{ + Code: requests.ParentAuthCertDecodeError, + Err: err, + } + } + cert, err := x509.ParseCertificate(certbytes) + if err != nil { + return nil, &CAError{ + Code: requests.ParentAuthCertParseError, + Err: err, + } + } + if cert != nil { + publicKey = cert.PublicKey + } else { + return nil, &CAError{ + Code: requests.ParentAuthCertParseError, + Err: errors.New("Public Key in Certificate missing"), + } + } + parentlogcerts, err := rainsclientlog.QueryMapServerZoneInfo(parentzone, myca.mapID, myca.MapServerAddr, myca.MapServerPkeyPath) + if err != nil { + return nil, &CAError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + validParentCerts := myca.FilterValidCertsFromChains(parentlogcerts, parentzone) + + if _, ok, err := myca.VerifyParentCertificate(validParentCerts, cert, parentzone); !ok { + return nil, &CAError{ + Code: requests.ParentAuthCertInvalid, + Err: err, + } + } + logger.Info("CA: Parent Certificate Verified") + default: + return nil, &CAError{ + Code: requests.AuthTypeMissing, + Err: errors.New(requests.ErrorMsg[requests.AuthTypeMissing]), + } + } + + // signature verification + if ok, err := VerifyNewDlgReqSignature(preq, publicKey); ok { + } else { + return nil, &CAError{ + Code: requests.InvalidSignature, + Err: err, + } + } + logger.Info("CA: Parent Signature Verified") + + // returns a list of certchains ( = list of certs, with chain bottom being index 0) => we are looking for [0][0], [1][0], ... + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, myca.mapID, myca.MapServerAddr, myca.MapServerPkeyPath) + if err != nil { + return nil, &CAError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + + validCerts := myca.FilterValidCertsFromChains(logcerts, childzone) + logger.Info(fmt.Sprintf("%d valid unrevoked certificates received from log", len(validCerts))) + + independentvalidCerts := common.FilterIndependentZoneCerts(validCerts) + logger.Info(fmt.Sprintf("%d valid unrevoked certificates for independent zones received from log", len(independentvalidCerts))) + + if len(independentvalidCerts) != 0 { + return nil, &CAError{ + Code: requests.ConflictingCertInLog, + Err: errors.New(requests.ErrorMsg[requests.ConflictingCertInLog]), + } + } + + + // creating certificate + // TODO: check csr for CA public key or ID + var IndependentSubZone bool + switch strings.ToLower(preq.Payload.IndependentSubZone) { + case "yes": + IndependentSubZone = true + case "no": + IndependentSubZone = false + default: + IndependentSubZone = false + } + + certbytes, err := myca.IssueCertificate(csr, IndependentSubZone) + if err != nil { + return nil, &CAError{ + Code: requests.CertIssueError, + Err: err, + } + } + logger.Info("CA: Issued Certificate") + return certbytes, nil +} + +func (myca *Ca) ProcessReNewDlgRequest(preq requests.ReNewDlgRequest) ([]byte, *CAError) { + logger.Info("CA: Processing ReNewDlg Request") + csrbytes, err := common.DecodeBase64(preq.Csr) + if err != nil { + return nil, &CAError{ + Code: requests.CsrDecodeError, + Err: err, + } + } + csr, err := x509.ParseCertificateRequest(csrbytes) + if err != nil { + return nil, &CAError{ + Code: requests.CsrParseError, + Err: err, + } + } + if err := csr.CheckSignature(); err != nil { + return nil, &CAError{ + Code: requests.CsrSignatureInvalid, + Err: err, + } + } + var childzone string + if len(csr.DNSNames) > 0 { + childzone = csr.DNSNames[0] + } else { + return nil, &CAError{ + Code: requests.CsrSANDNSMissing, + Err: errors.New(requests.ErrorMsg[requests.CsrSANDNSMissing]), + } + } + + // returns a list of certchains ( = list of certs, with chain bottom being index 0) => we are looking for [0][0], [1][0], ... + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, myca.mapID, myca.MapServerAddr, myca.MapServerPkeyPath) + if err != nil { + return []byte{}, &CAError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + + validCerts := myca.FilterValidCertsFromChains(logcerts, childzone) + + + ok, IsIndZone := CheckForExistingCert(validCerts, *csr) + if !ok { + return nil, &CAError{ + Code: requests.RequiredCertNotInLog, + Err: errors.New(requests.ErrorMsg[requests.RequiredCertNotInLog]), + } + } + + // creating certificate + // TODO: check csr for CA public key or ID + certbytes, err := myca.IssueCertificate(csr, IsIndZone) + if err != nil { + return nil, &CAError{ + Code: requests.CertIssueError, + Err: err, + } + } + logger.Info("CA: Issued Certificate") + return certbytes, nil +} + +func (myca *Ca) ProcessKeyChangeDlgRequest(preq requests.KeyChangeDlgRequest) ([]byte, *CAError) { + logger.Info("CA: Processing KeyChangeDlg Request") + csrbytes, err := common.DecodeBase64(preq.Csr) + if err != nil { + return nil, &CAError{ + Code: requests.CsrDecodeError, + Err: err, + } + } + csr, err := x509.ParseCertificateRequest(csrbytes) + if err != nil { + return nil, &CAError{ + Code: requests.CsrParseError, + Err: err, + } + } + if err := csr.CheckSignature(); err != nil { + return nil, &CAError{ + Code: requests.CsrSignatureInvalid, + Err: err, + } + } + var childzone string + if len(csr.DNSNames) > 0 { + childzone = csr.DNSNames[0] + } else { + return nil, &CAError{ + Code: requests.CsrSANDNSMissing, + Err: errors.New(requests.ErrorMsg[requests.CsrSANDNSMissing]), + } + } + + // returns a list of certchains ( = list of certs, with chain bottom being index 0) => we are looking for [0][0], [1][0], ... + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, myca.mapID, myca.MapServerAddr, myca.MapServerPkeyPath) + if err != nil { + return nil, &CAError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + + validCerts := myca.FilterValidCertsFromChains(logcerts, childzone) + + var oldPublicKey interface{} + oldPublicKey, err = common.DecodePublicKey(preq.OldKey, preq.OldKeyAlg) + if err != nil { + return nil, &CAError{ + Code: requests.OldKeyDecodeError, + Err: err, + } + } + + ok, IsIndZone := CheckForExistingCertKeyChange(validCerts, *csr, oldPublicKey) + if !ok { + return nil, &CAError{ + Code: requests.RequiredCertNotInLog, + Err: errors.New(requests.ErrorMsg[requests.RequiredCertNotInLog]), + } + } + + if ok, err := VerifyKeyChangeSignature(preq, oldPublicKey); !ok { + return nil, &CAError{ + Code: requests.InvalidSignature, + Err: err, + } + } + + // creating certificate + // TODO: check csr for CA public key or ID + certbytes, err := myca.IssueCertificate(csr, IsIndZone) + if err != nil { + return nil, &CAError{ + Code: requests.CertIssueError, + Err: err, + } + } + logger.Info("CA: Issued Certificate") + return certbytes, nil +} + + +func VerifyKeyChangeSignature(req requests.KeyChangeDlgRequest, publicKey interface{}) (bool, error) { + message, err := common.DecodeBase64(req.Csr) + if err != nil { + return false, err + } + + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err = common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func CheckForExistingParentCert(logcerts []x509.Certificate, pcert x509.Certificate) bool { + for _ , cert := range logcerts { + switch pcert.PublicKey.(type) { + case *rsa.PublicKey: + csrKey, _ := pcert.PublicKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := pcert.PublicKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + default: + continue + } + for i , name := range pcert.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + return true + } + return false +} + +func CheckForExistingCert(certs []x509.Certificate, csr x509.CertificateRequest) (bool, bool) { + for _ , cert := range certs { + switch csr.PublicKey.(type) { + case *rsa.PublicKey: + csrKey, _ := csr.PublicKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := csr.PublicKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + default: + continue + } + for i , name := range csr.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + IsIndependentZone, _ := common.CheckIndFlagX509Cert(cert) + return true, IsIndependentZone + } + return false, false +} + +func CheckForExistingCertKeyChange(certs []x509.Certificate, csr x509.CertificateRequest, pubKey interface{}) (bool, bool) { + for _ , cert := range certs { + switch pubKey.(type) { + case *rsa.PublicKey: + csrKey, _ := pubKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := pubKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + } + for i , name := range csr.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + IsIndependentZone, _ := common.CheckIndFlagX509Cert(cert) + return true, IsIndependentZone + } + return false, false +} + +func (myca *Ca) FilterValidCertsFromChains(certchains [][]x509.Certificate, zone string) ([]x509.Certificate) { + var validCerts []x509.Certificate + for _, certchain := range certchains { + cert := certchain[0] + if _, err := cert.Verify(x509.VerifyOptions{ + DNSName: zone, + Intermediates: nil, + Roots: myca.CertPool, + CurrentTime: time.Time{}, + KeyUsages: nil, + MaxConstraintComparisions: 0, + }); err == nil { + validCerts = append(validCerts, cert) + } + } + return validCerts +} + +func (myca *Ca) IssueCertificate(csr *x509.CertificateRequest, IsIndependentSubzone bool) ([]byte, error) { + + RhineExt, _ := common.CreateIndFlagExt(IsIndependentSubzone) + + certTemplate := x509.Certificate{ + SerialNumber: big.NewInt(123), + Issuer: myca.CACertificate.Issuer, + Subject: csr.Subject, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 356), + BasicConstraintsValid: true, + IsCA: false, + KeyUsage: x509.KeyUsageDigitalSignature, + DNSNames: []string{csr.DNSNames[0]}, + } + certTemplate.ExtraExtensions = append(certTemplate.ExtraExtensions, RhineExt) + + certbytes, err := x509.CreateCertificate(rand.Reader, &certTemplate, myca.CACertificate, csr.PublicKey, myca.PrivateKey) + if err != nil { + return []byte{}, err + } + return certbytes, nil +} + + +func DecodeNewDlgRequest(r *http.Request) (*requests.NewDlgRequest, *CAError) { + var req requests.NewDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CAError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + if req.Header.Parent_auth_type == "certificate" && req.Header.Parent_cert == "" { + return nil, &CAError{ + Code: requests.ParentCertificateMissing, + Err: errors.New(requests.ErrorMsg[requests.ParentCertificateMissing]), + } + } + if req.Header.Parent_auth_type == "dnssec" && !(req.Header.Alg == "RSA" || req.Header.Alg == "Ed25519"){ + return nil, &CAError{ + Code: requests.UnsupportedAlg, + Err: errors.New(requests.ErrorMsg[requests.UnsupportedAlg]), + } + } + if req.Payload.Csr == "" { + return nil, &CAError{ + Code: requests.CSRMissing, + Err: errors.New(requests.ErrorMsg[requests.CSRMissing]), + } + } + return &req, nil +} + +func DecodeReNewDlgRequest(r *http.Request) (*requests.ReNewDlgRequest, *CAError) { + var req requests.ReNewDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CAError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + if req.Csr == "" { + return nil, &CAError{ + Code: requests.CSRMissing, + Err: errors.New(requests.ErrorMsg[requests.CSRMissing]), + } + } + return &req, nil +} + +func DecodeKeyChangeDlgRequest(r *http.Request) (*requests.KeyChangeDlgRequest, *CAError) { + var req requests.KeyChangeDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CAError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + if req.Csr == "" { + return nil, &CAError{ + Code: requests.CSRMissing, + Err: errors.New(requests.ErrorMsg[requests.CSRMissing]), + } + } + return &req, nil +} + +func VerifyNewDlgReqSignature(req requests.NewDlgRequest, publicKey interface{}) (bool, error) { + headerSig, _ := json.Marshal(req.Header) + payloadSig, _ := json.Marshal(req.Payload) + message := append(headerSig, payloadSig...) + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err := common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + return false, err + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func (myca *Ca) VerifyParentCertificate(logcerts []x509.Certificate, cert *x509.Certificate, parentzone string) ([][]*x509.Certificate, bool, error) { + certPool := myca.CertPool + + opts := x509.VerifyOptions{ + DNSName: parentzone, + Intermediates: nil, + Roots: certPool, + CurrentTime: time.Time{}, + KeyUsages: nil, + MaxConstraintComparisions: 0, + } + certchains, err := cert.Verify(opts) + if err != nil { + fmt.Println(certchains) + logger.Warn(fmt.Sprintln("error verifying parent cert: ", err)) + return certchains, false, err + } + if !CheckForExistingParentCert(logcerts, *cert) { + return nil, false, errors.New("Parent Certificate not in Log Certs list") + } + return certchains, true, err + +} + + diff --git a/offlineauth/ca/ca_server.go b/offlineauth/ca/ca_server.go new file mode 100644 index 00000000..1ced2710 --- /dev/null +++ b/offlineauth/ca/ca_server.go @@ -0,0 +1,122 @@ +package ca + +import ( + "encoding/json" + "fmt" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/requests" + "log" + "net/http" + +) + + +func (myca *Ca) NewDlg(w http.ResponseWriter, r *http.Request) { + + logger.Info("CA: Received NewDlg Request") + preq, err := DecodeNewDlgRequest(r) + if err != nil { + log.Println("CA: Error Decoding Request") + resp := requests.CAResponse{Error: "malformed request"} + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + log.Printf("CA: Decoded Request: %#v\n", preq) + + certbytes, CAErr := myca.ProcessNewDlgRequest(*preq) + + if CAErr != nil { + logger.Warn(fmt.Sprintln("CA: Error Processing NewDlg Req: ", requests.ErrorMsg[CAErr.Code])) + resp := requests.CAResponse{Error: requests.ErrorMsg[CAErr.Code]} + log.Printf("CA: NewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } else { + resp := requests.CAResponse{Cert: common.EncodeBase64(certbytes)} + log.Printf("CA: NewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } + +} + +func (myca *Ca) KeyChangeDlg(w http.ResponseWriter, r *http.Request) { + log.Println("CA: Received KeyChangeDlg Request") + req, err := DecodeKeyChangeDlgRequest(r) + if err != nil { + log.Println("CA: Error Decoding Request") + resp := requests.CAResponse{Error: "malformed request"} + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + log.Printf("CA: Decoded Request: %#v\n", req) + + certbytes, CAErr := myca.ProcessKeyChangeDlgRequest(*req) + + if CAErr != nil { + logger.Warn(fmt.Sprintln("CA: Error Processing KeyChangeDlg Req: ", requests.ErrorMsg[CAErr.Code])) + resp := requests.CAResponse{Error: requests.ErrorMsg[CAErr.Code]} + log.Printf("CA: KeyChangeDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } else { + resp := requests.CAResponse{Cert: common.EncodeBase64(certbytes)} + log.Printf("CA: KeyChangeDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } + +} + +func (myca *Ca) ReNewDlg(w http.ResponseWriter, r *http.Request) { + + log.Println("CA: Received ReNewDlg Request") + req, err := DecodeReNewDlgRequest(r) + if err != nil { + log.Println("CA: Error Decoding Request") + resp := requests.CAResponse{Error: "malformed request"} + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + log.Printf("CA: Decoded Request: %#v\n", req) + + certbytes, CAErr := myca.ProcessReNewDlgRequest(*req) + + if CAErr != nil { + logger.Warn(fmt.Sprintln("CA: Error Processing ReNewDlg Req: ", requests.ErrorMsg[CAErr.Code])) + resp := requests.CAResponse{Error: requests.ErrorMsg[CAErr.Code]} + log.Printf("CA: ReNewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } else { + resp := requests.CAResponse{Cert: common.EncodeBase64(certbytes)} + log.Printf("CA: NewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + } + + +} + +func (myca *Ca) RunServer(addr string) { + http.HandleFunc("/NewDlg", myca.NewDlg) + http.HandleFunc("/KeyChangeDlg", myca.KeyChangeDlg) + http.HandleFunc("/ReNewDlg", myca.ReNewDlg) + log.Fatal(http.ListenAndServe(addr, nil)) // TODO HTTPS + +} diff --git a/offlineauth/ca/caconfig.go b/offlineauth/ca/caconfig.go new file mode 100644 index 00000000..59b9eee9 --- /dev/null +++ b/offlineauth/ca/caconfig.go @@ -0,0 +1,12 @@ +package ca + +type Config struct { + PrivateKeyAlgorithm string + PrivateKeyPath string + CertificatePath string + MapServerAddress string + MapServerPublicKeyPath string + MapId int64 + ServerAddress string + RootCertsPath string +} diff --git a/offlineauth/checkerExtension/checker.go b/offlineauth/checkerExtension/checker.go new file mode 100644 index 00000000..73682d63 --- /dev/null +++ b/offlineauth/checkerExtension/checker.go @@ -0,0 +1,764 @@ +package checkerExtension + +import ( + "crypto" + "crypto/ed25519" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + logger15 "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/rainsclientlog" + "github.com/robinburkhard/rainsdeleg/requests" + "io/ioutil" + "log" + "net/http" + "time" +) + +var logger = logger15.New("Module", "CheckerExtension") + +type Checker struct { + Address string + LogID int64 + LogAddress string + LogPkeyPath string + MapID int64 + MapAddress string + MapPkeyPath string + CertPool *x509.CertPool +} + +type CheckerError struct { + Code int + Err error +} + +func (e *CheckerError) Error() string { + return fmt.Sprintf("code: %s, err: %s", e.Code, e.Err) +} + +func LoadConfig(Path string) (Config, error) { + conf := Config{} + file, err := ioutil.ReadFile(Path) + if err != nil { + return Config{}, err + } + if err = json.Unmarshal(file, &conf); err != nil { + return Config{}, err + } + + return conf, nil +} + +func NewChecker(config Config) *Checker { + CheckerCertPool, err := x509.SystemCertPool() + if err == nil { + CheckerCertPool = x509.NewCertPool() + } + + checker := Checker{ + LogID: config.LogID, + LogAddress: config.LogAddress, + LogPkeyPath: config.LogPkeyPath, + MapID: config.MapID, + MapAddress: config.MapAddress, + MapPkeyPath: config.MapPkeyPath, + CertPool: CheckerCertPool, + Address: config.ServerAddress, + + } + + files, err := ioutil.ReadDir(config.RootCertsPath) + if err != nil { + log.Fatal("Error reading roots directory: ", err) + } + + for _, file := range files { + pemfile, _ := ioutil.ReadFile(config.RootCertsPath + file.Name()) + if checker.CertPool.AppendCertsFromPEM(pemfile) { + logger.Warn("Added " + file.Name()+ " to trust root") + } + } + + return &checker +} + + +func DecodeCheckNewDlgRequest(r *http.Request) (*requests.CheckNewDlgRequest, *CheckerError) { + logger.Info("Checker: Decoding CheckNewDlg Request") + var req requests.CheckNewDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CheckerError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + return &req, nil +} + +func DecodeCheckReNewDlgRequest(r *http.Request) (*requests.CheckReNewDlgRequest, *CheckerError) { + logger.Info("Checker: Decoding CheckReNewDlg Request") + var req requests.CheckReNewDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CheckerError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + return &req, nil +} + +func DecodeCheckKeyChangeDlgRequest(r *http.Request) (*requests.CheckKeyChangeDlgRequest, *CheckerError) { + logger.Info("Checker: Decoding CheckReNewDlg Request") + var req requests.CheckKeyChangeDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CheckerError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + return &req, nil +} + +func DecodeRevokeDlgRequest(r *http.Request) (*requests.RevokeDlgRequest, *CheckerError) { + logger.Info("Checker: Decoding RevokeDlg Request") + var req requests.RevokeDlgRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + return nil, &CheckerError{ + Code: requests.JSONDecodeError, + Err: err, + } + } + return &req, nil +} + +func (c *Checker) ProcessCheckNewDlgRequest(preq requests.CheckNewDlgRequest) (*x509.Certificate, *CheckerError) { + logger.Info("Checker: Processing CheckNewDlg Request") + + // parse child cert + childCertBytes, err := common.DecodeBase64(preq.Payload.Cert) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertDecodeError, + Err: err, + } + } + childCert, err := x509.ParseCertificate(childCertBytes) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertParseError, + Err: err, + } + } + + // read parent zone + childzone := childCert.DNSNames[0] + parentzone := common.GetParentZone(childzone) + var publicKey interface{} + + // parent authentication + switch preq.Header.Parent_auth_type { + case "NOAUTH": + // TODO REMOVE + // only for testing + logger.Crit("NO PARENT AUTHENTICATION TYPE (TESTING)") + publicKey, _ = common.DecodePublicKey(preq.Header.Pubkey, preq.Header.Alg) + + case "dnssec": + logger.Info("Checker: Authenticating Parent: DNSSEC") + var err error + switch preq.Header.Alg { + case "RSA": + publicKey, err = common.QueryDNSKeyRSA(parentzone) + case "Ed25519": + publicKey, err = common.QueryDNSKeyEd25519(parentzone) + } + + if err != nil { + return nil, &CheckerError{ + Code: requests.ParentAuthDNSSECFailed, + Err: err, + } + } + logger.Info("Checker: Authenticated Parent DNSSEC") + + + case "certificate": + logger.Info("Checker: Authenticating Parent: Certificate") + certbytes, err := common.DecodeBase64(preq.Header.Parent_cert) + if err != nil { + return nil, &CheckerError{ + Code: requests.ParentAuthCertDecodeError, + Err: err, + } + } + parentcert, err := x509.ParseCertificate(certbytes) + if err != nil { + return nil, &CheckerError{ + Code: requests.ParentAuthCertParseError, + Err: err, + } + } + if parentcert != nil { + publicKey = parentcert.PublicKey + } else { + return nil, &CheckerError{ + Code: requests.ParentAuthCertParseError, + Err: errors.New("Public Key in Certificate missing"), + } + } + + parentlogcerts, err := rainsclientlog.QueryMapServerZoneInfo(parentzone, c.MapID, c.MapAddress, c.MapPkeyPath) + if err != nil { + return nil, &CheckerError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + validParentCerts := c.FilterValidCertsFromChains(parentlogcerts, parentzone) + + if _, ok, err := c.VerifyParentCertificate(validParentCerts, parentcert, parentzone); !ok { + return nil, &CheckerError{ + Code: requests.ParentAuthCertInvalid, + Err: err, + } + } + logger.Info("Checker: Parent Certificate Verified") + default: + return nil, &CheckerError{ + Code: requests.AuthTypeMissing, + Err: errors.New(requests.ErrorMsg[requests.AuthTypeMissing]), + } + } + + //verify parent sig + if ok, err := VerifyCheckNewDlgReqSignature(preq, publicKey); ok { + } else { + return nil, &CheckerError{ + Code: requests.InvalidSignature, + Err: err, + } + } + logger.Info("Checker: Parent Signature Verified") + + // verify child cert + if _, ok, err := c.VerifyChildCertificate(childCert); !ok { + return nil, &CheckerError{ + Code: requests.CertInvalid, + Err: err, + } + } + logger.Info("Checker: Child Certificate Verified") + + + return childCert, nil +} + +func (c *Checker) ProcessCheckReNewDlgRequest(req requests.CheckReNewDlgRequest) (*x509.Certificate, *CheckerError) { + logger.Info("Checker: Processing CheckReNewDlg Request") + + // parse child cert + childCertBytes, err := common.DecodeBase64(req.Cert) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertDecodeError, + Err: err, + } + } + childCert, err := x509.ParseCertificate(childCertBytes) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertParseError, + Err: err, + } + } + + childzone := childCert.DNSNames[0] + var publicKey interface{} + publicKey = childCert.PublicKey + + if ok, err := VerifyCheckReNewDlgReqSignature(req, publicKey); ok { + } else { + return nil, &CheckerError{ + Code: requests.InvalidSignature, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg Signature Verified") + + // verify child cert + if _, ok, err := c.VerifyChildCertificate(childCert); !ok { + return nil, &CheckerError{ + Code: requests.CertInvalid, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg Child Cert Verified") + + + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, c.MapID, c.MapAddress, c.MapPkeyPath) + if err != nil { + return nil, &CheckerError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg: Map Queried") + + + validCerts := c.FilterValidCertsFromChains(logcerts, childzone) + + if ok := CheckForExistingCert(validCerts, *childCert); !ok { + return nil, &CheckerError{ + Code: requests.RequiredCertNotInLog, + Err: errors.New(requests.ErrorMsg[requests.RequiredCertNotInLog]), + } + } + + logger.Info("Checker: ReNewDlg: Existing Cert in Log found, New Certificate Approved") + + + + logger.Info("Checker: Request OK") + return childCert, nil + +} + +func (c *Checker) ProcessCheckKeyChangeDlgRequest(req requests.CheckKeyChangeDlgRequest) (*x509.Certificate, *CheckerError) { + logger.Info("Checker: Processing CheckKeyChangeDlg Request") + + // parse child cert + childCertBytes, err := common.DecodeBase64(req.Cert) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertDecodeError, + Err: err, + } + } + childCert, err := x509.ParseCertificate(childCertBytes) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertParseError, + Err: err, + } + } + + childzone := childCert.DNSNames[0] + + var oldPublicKey interface{} + oldPublicKey, err = common.DecodePublicKey(req.OldKey, req.OldKeyAlg) + if err != nil { + return nil, &CheckerError{ + Code: requests.OldKeyDecodeError, + Err: err, + } + } + + if ok, err := VerifyKeyChangeSignature(req, oldPublicKey); ok { + } else { + return nil, &CheckerError{ + Code: requests.InvalidSignature, + Err: err, + } + } + logger.Info("Checker: KeyChangeDlg Signature Verified") + + // verify child cert + if _, ok, err := c.VerifyChildCertificate(childCert); !ok { + return nil, &CheckerError{ + Code: requests.CertInvalid, + Err: err, + } + } + logger.Info("Checker: ReNewDlg Child Cert Verified") + + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, c.MapID, c.MapAddress, c.MapPkeyPath) + if err != nil { + return nil, &CheckerError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + logger.Info("Checker: ReNewDlg: Map Queried") + + + validCerts := c.FilterValidCertsFromChains(logcerts, childzone) + + if ok := CheckForExistingCertKeyChange(validCerts, *childCert, oldPublicKey); !ok { + return nil, &CheckerError{ + Code: requests.RequiredCertNotInLog, + Err: errors.New(requests.ErrorMsg[requests.RequiredCertNotInLog]), + } + } + + logger.Info("Checker: ReNewDlg: Existing Cert in Log found, New Certificate Approved") + + logger.Info("Checker: Request OK") + return childCert, nil + +} + +func (c *Checker) ProcessRevokeDlgRequest(req requests.RevokeDlgRequest) (*x509.Certificate, *CheckerError) { + logger.Info("Checker: Processing RevokeDlg Request") + + // parse child cert + childCertBytes, err := common.DecodeBase64(req.Cert) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertDecodeError, + Err: err, + } + } + childCert, err := x509.ParseCertificate(childCertBytes) + if err != nil { + return nil, &CheckerError{ + Code: requests.CertParseError, + Err: err, + } + } + + childzone := childCert.DNSNames[0] + var publicKey interface{} + publicKey = childCert.PublicKey + + if ok, err := VerifyRevokeDlgReqSignature(req, publicKey); ok { + } else { + return nil, &CheckerError{ + Code: requests.InvalidSignature, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg Signature Verified") + + // verify child cert + if _, ok, err := c.VerifyChildCertificate(childCert); !ok { + return nil, &CheckerError{ + Code: requests.CertInvalid, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg Child Cert Verified") + + + logcerts, err := rainsclientlog.QueryMapServerZoneInfo(childzone, c.MapID, c.MapAddress, c.MapPkeyPath) + if err != nil { + return nil, &CheckerError{ + Code: requests.MapServerConnectionFailed, + Err: err, + } + } + + logger.Info("Checker: ReNewDlg: Map Queried") + + + validCerts := c.FilterValidCertsFromChains(logcerts, childzone) + + if ok := FindCert(validCerts, *childCert); !ok { + return nil, &CheckerError{ + Code: requests.RequiredCertNotInLog, + Err: errors.New(requests.ErrorMsg[requests.RequiredCertNotInLog]), + } + } + + logger.Info("Checker: Request OK") + return childCert, nil + +} + +func VerifyKeyChangeSignature(req requests.CheckKeyChangeDlgRequest, publicKey interface{}) (bool, error) { + message, err := common.DecodeBase64(req.Cert) + if err != nil { + return false, err + } + + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err = common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + return false, err + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func CheckForExistingCert(certs []x509.Certificate, reqCert x509.Certificate) bool { + for _ , cert := range certs { + switch reqCert.PublicKey.(type) { + case *rsa.PublicKey: + csrKey, _ := reqCert.PublicKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := reqCert.PublicKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + default: + continue + } + for i , name := range reqCert.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + return true + } + return false +} + +func FindCert(certs []x509.Certificate, reqCert x509.Certificate) bool { + for _ , cert := range certs { + if cert.Equal(&reqCert) { + logger.Info("Cert to Revoke found in Log (valid)") + return true + } + + } + return false +} + +func CheckForExistingCertKeyChange(certs []x509.Certificate, reqCert x509.Certificate, pubKey interface{}) bool { + for _ , cert := range certs { + switch pubKey.(type) { + case *rsa.PublicKey: + csrKey, _ := pubKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := pubKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + } + for i , name := range reqCert.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + return true + } + return false +} + +func (c *Checker) FilterValidCertsFromChains(certchains [][]x509.Certificate, zone string) ([]x509.Certificate) { + var validCerts []x509.Certificate + for _, certchain := range certchains { + cert := certchain[0] + if _, err := cert.Verify(x509.VerifyOptions{ + DNSName: zone, + Intermediates: nil, + Roots: c.CertPool, + CurrentTime: time.Time{}, + KeyUsages: nil, + MaxConstraintComparisions: 0, + }); err == nil { + validCerts = append(validCerts, cert) + } + } + return validCerts +} + +func VerifyCheckReNewDlgReqSignature(req requests.CheckReNewDlgRequest, publicKey interface{}) (bool, error) { + message, _ := common.DecodeBase64(req.Cert) + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err := common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + return false, err + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func VerifyRevokeDlgReqSignature(req requests.RevokeDlgRequest, publicKey interface{}) (bool, error) { + certbytes, _ := common.DecodeBase64(req.Cert) + message := append([]byte("Revoke"), certbytes...) + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err := common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + return false, err + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func VerifyCheckNewDlgReqSignature(req requests.CheckNewDlgRequest, publicKey interface{}) (bool, error) { + headerSig, _ := json.Marshal(req.Header) + payloadSig, _ := json.Marshal(req.Payload) + message := append(headerSig, payloadSig...) + sha256 := sha256.New() + sha256.Write(message) + digest := sha256.Sum(nil) + + byteSig := []byte{} + byteSig, err := common.DecodeBase64(req.Signature) + if err != nil { + fmt.Println("error decoding b64 signature", err) + return false, err + } + + switch publicKey.(type) { + case *rsa.PublicKey: + err := rsa.VerifyPSS(publicKey.(*rsa.PublicKey), crypto.SHA256, digest, byteSig, nil) + if err != nil { + logger.Warn("signature error") + return false, err + } + return true, nil + case ed25519.PublicKey: + if !ed25519.Verify(publicKey.(ed25519.PublicKey), message, byteSig) { + logger.Warn("signature error") + return false, err + } + return true, nil + default: + return false, errors.New("unsupported key") + } +} + +func (c *Checker) VerifyChildCertificate(cert *x509.Certificate,) ([][]*x509.Certificate, bool, error) { + certPool := c.CertPool + + opts := x509.VerifyOptions{ + Roots: certPool, + CurrentTime: time.Time{}, + KeyUsages: nil, + MaxConstraintComparisions: 0, + } + certchains, err := cert.Verify(opts) + if err != nil { + fmt.Println(certchains) + logger.Warn(fmt.Sprintln("error verifying child cert: ", err)) + return certchains, false, err + } + return certchains, true, err + +} + +func (c *Checker) VerifyParentCertificate(logcerts []x509.Certificate, cert *x509.Certificate, parentzone string) ([][]*x509.Certificate, bool, error) { + certPool := c.CertPool + + opts := x509.VerifyOptions{ + DNSName: parentzone, + Intermediates: nil, + Roots: certPool, + CurrentTime: time.Time{}, + KeyUsages: nil, + MaxConstraintComparisions: 0, + } + certchains, err := cert.Verify(opts) + if err != nil { + fmt.Println(certchains) + logger.Warn(fmt.Sprintln("error verifying parent cert: ", err)) + return certchains, false, err + } + if !CheckForExistingParentCert(logcerts, *cert) { + return nil, false, errors.New("Parent Certificate not in Log Certs list") + } + return certchains, true, err + +} + +func CheckForExistingParentCert(logcerts []x509.Certificate, pcert x509.Certificate) bool { + for _ , cert := range logcerts { + switch pcert.PublicKey.(type) { + case *rsa.PublicKey: + csrKey, _ := pcert.PublicKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + case ed25519.PublicKey: + csrKey, _ := pcert.PublicKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + continue + } + default: + continue + } + for i , name := range pcert.DNSNames { + if !(name == cert.DNSNames[i]) { + continue + } + } + return true + } + return false +} + + diff --git a/offlineauth/checkerExtension/checker_server.go b/offlineauth/checkerExtension/checker_server.go new file mode 100644 index 00000000..7b7e7f9f --- /dev/null +++ b/offlineauth/checkerExtension/checker_server.go @@ -0,0 +1,146 @@ +package checkerExtension + +import ( + "encoding/json" + "fmt" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/rainsclientlog" + "github.com/robinburkhard/rainsdeleg/requests" + "log" + "net/http" + "time" +) + + +func (c *Checker) CheckNewDlg(w http.ResponseWriter, r *http.Request) { + req, err := DecodeCheckNewDlgRequest(r) + if err != nil { + fmt.Println(err) + return + } + cert, CheckerError := c.ProcessCheckNewDlgRequest(*req) + + if CheckerError != nil { + logger.Warn(fmt.Sprintln("Checker: Error Processing CheckNewDlg Req: ", requests.ErrorMsg[CheckerError.Code])) + resp := requests.CheckResponse{Status: "Failed", Error: requests.ErrorMsg[CheckerError.Code]} + log.Printf("Checker: CheckNewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + rainsclientlog.AddToLogServer(cert, c.LogID, c.LogAddress, c.LogPkeyPath) + time.Sleep(time.Second * 2) + if err := rainsclientlog.Mapping(c.MapPkeyPath, c.MapID, c.MapAddress, c.LogPkeyPath, c.LogID, c.LogAddress); err != nil { + log.Println(err) + } + + resp := requests.CheckResponse{Status: "OK"} + log.Printf("Checker: CheckNewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return +} + +func (c *Checker) CheckReNewDlg(w http.ResponseWriter, r *http.Request) { + req, err := DecodeCheckReNewDlgRequest(r) + if err != nil { + fmt.Println(err) + return + } + cert, CheckerError := c.ProcessCheckReNewDlgRequest(*req) + + if CheckerError != nil { + logger.Warn(fmt.Sprintln("Checker: Error Processing CheckReNewDlg Req: ", requests.ErrorMsg[CheckerError.Code])) + resp := requests.CheckResponse{Status: "Failed", Error: requests.ErrorMsg[CheckerError.Code]} + log.Printf("Checker: CheckNewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + rainsclientlog.AddToLogServer(cert, c.LogID, c.LogAddress, c.LogPkeyPath) + time.Sleep(time.Second * 2) + if err := rainsclientlog.Mapping(c.MapPkeyPath, c.MapID, c.MapAddress, c.LogPkeyPath, c.LogID, c.LogAddress); err != nil { + log.Println(err) + } + + resp := requests.CheckResponse{Status: "OK"} + log.Printf("Checker: CheckNewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return +} + +func (c *Checker) CheckKeyChangeDlg(w http.ResponseWriter, r *http.Request) { + req, err := DecodeCheckKeyChangeDlgRequest(r) + if err != nil { + fmt.Println(err) + return + } + cert, CheckerError := c.ProcessCheckKeyChangeDlgRequest(*req) + + if CheckerError != nil { + logger.Warn(fmt.Sprintln("Checker: Error Processing CheckKeyChangeDlg Req: ", requests.ErrorMsg[CheckerError.Code])) + resp := requests.CheckResponse{Status: "Failed", Error: requests.ErrorMsg[CheckerError.Code]} + log.Printf("Checker: CheckNewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + rainsclientlog.AddToLogServer(cert, c.LogID, c.LogAddress, c.LogPkeyPath) + time.Sleep(time.Second * 2) + if err := rainsclientlog.Mapping(c.MapPkeyPath, c.MapID, c.MapAddress, c.LogPkeyPath, c.LogID, c.LogAddress); err != nil { + log.Println(err) + } + + resp := requests.CheckResponse{Status: "OK"} + log.Printf("Checker: CheckNewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return +} + +func (c *Checker) RevokeDlg(w http.ResponseWriter, r *http.Request) { + req, err := DecodeRevokeDlgRequest(r) + if err != nil { + fmt.Println(err) + return + } + cert, CheckerError := c.ProcessRevokeDlgRequest(*req) + + if CheckerError != nil { + logger.Warn(fmt.Sprintln("Checker: Error Processing CheckReNewDlg Req: ", requests.ErrorMsg[CheckerError.Code])) + resp := requests.CheckResponse{Status: "Failed", Error: requests.ErrorMsg[CheckerError.Code]} + log.Printf("Checker: CheckNewDlgReq FAILED: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return + } + + rainsclientlog.RevokeCert(cert, c.MapPkeyPath, c.MapID, c.MapAddress) + + resp := requests.CheckResponse{Status: "OK"} + log.Printf("Checker: CheckNewDlgReq OK: Response: %#v", resp) + jsonresp, _ := json.Marshal(resp) + w.Header().Set("Content-Type", "application/json") + w.Write(jsonresp) + return +} + + +func (c *Checker) RunServer(addr string) { + logger.Info("CheckerExt: Started") + http.HandleFunc("/CheckNewDlg", c.CheckNewDlg) + http.HandleFunc("/CheckReNewDlg", c.CheckReNewDlg) + http.HandleFunc("/CheckKeyChangeDlg", c.CheckKeyChangeDlg) + http.HandleFunc("/RevokeDlg", c.RevokeDlg) + log.Fatal(http.ListenAndServe(addr, nil)) // TODO HTTPS +} diff --git a/offlineauth/checkerExtension/checkerconfig.go b/offlineauth/checkerExtension/checkerconfig.go new file mode 100644 index 00000000..37732cac --- /dev/null +++ b/offlineauth/checkerExtension/checkerconfig.go @@ -0,0 +1,12 @@ +package checkerExtension + +type Config struct { + LogID int64 + LogAddress string + LogPkeyPath string + MapID int64 + MapAddress string + MapPkeyPath string + RootCertsPath string + ServerAddress string +} diff --git a/offlineauth/child/child.go b/offlineauth/child/child.go new file mode 100644 index 00000000..5d64d568 --- /dev/null +++ b/offlineauth/child/child.go @@ -0,0 +1,387 @@ +package child + +import ( + "bytes" + "crypto" + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "errors" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/requests" + "log" + "net/http" +) + +func CreateCSR(zone string, CA string, privKey interface{}) ([]byte, error) { + // TODO put CA public key or ID in request + var req x509.CertificateRequest + req.DNSNames = append(req.DNSNames, zone) + req.Subject.CommonName = "RHINE:"+zone + certReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &req, privKey) + if err != nil { + //log.Println("error creating CSR: ", err) + return nil, err + } + return certReqBytes, nil +} + +func ReNewDlg(Cert *x509.Certificate, privKey interface{}, CAAddress string, CheckerAddress string) ([]byte, error){ + newReq, err := CreateReNewDlgRequest(Cert, privKey) + if err != nil { + return nil, err + } + resp, err := PostReNewDlgRequest(*newReq, CAAddress) + if err != nil { + return nil, err + } + if resp.Cert == ""{ + return nil, errors.New(resp.Error) + } + + certbytes, _ := common.DecodeBase64(resp.Cert) + + log.Println("ReNewDlg: Cert obtained") + + checkReNewReq, err := CreateCheckReNewDlgRequest(certbytes, privKey) + if err != nil { + return nil, err + } + + checkresp, err := PostCheckReNewDlgRequest(*checkReNewReq, CheckerAddress) + if err != nil { + return nil, err + } + if checkresp.Status != "OK"{ + return nil, errors.New(checkresp.Error) + } + + log.Println("CheckReNewDlg: Cert added") + + return certbytes, nil +} + +func KeyChangeDlg(Cert *x509.Certificate, privKey interface{}, newprivKey interface{}, CAAddress string, CheckerAddress string) ([]byte, error){ + keyChangeReq, err := CreateKeyChangeDlgRequest(Cert, privKey, newprivKey) + if err != nil { + return nil, err + } + resp, err := PostKeyChangeDlgReq(*keyChangeReq, CAAddress) + if err != nil { + return nil, err + } + if resp.Cert == ""{ + return nil, errors.New(resp.Error) + } + + certbytes, _ := common.DecodeBase64(resp.Cert) + + log.Println("KeyChangeDlg: Cert obtained") + + checkKeyChangeReq, err := CreateCheckKeyChangeDlgReq(certbytes, privKey) + if err != nil { + return nil, err + } + + checkresp, err := PostCheckKeyChangeDlgRequest(*checkKeyChangeReq, CheckerAddress) + if err != nil { + return nil, err + } + if checkresp.Status != "OK"{ + return nil, errors.New(checkresp.Error) + } + + log.Println("CheckKeyChangeDlg: Cert added") + + return certbytes, nil +} + +func RevokeDlg(Cert *x509.Certificate, privKey interface{}, CheckerAddress string) (error){ + revReq, err := CreateRevokeDlgRequest(Cert.Raw, privKey) + if err != nil { + return err + } + + checkresp, err := PostRevokeDlgRequest(*revReq, CheckerAddress) + if err != nil { + return err + } + if checkresp.Status != "OK"{ + return errors.New(checkresp.Error) + } + + log.Println("RevokeDlg: Certificate Revoked") + + return nil +} + +func CreateRevokeDlgRequest(cert []byte, privkey interface{}) (*requests.RevokeDlgRequest, error){ + sigbytes := []byte{} + + message := append([]byte("Revoke"), cert...) + + switch privkey.(type) { + case ed25519.PrivateKey: + sigbytes = ed25519.Sign(privkey.(ed25519.PrivateKey), message) + case *rsa.PrivateKey: + sha256 := sha256.New() + sha256.Write(message) + hash := sha256.Sum(nil) + sigbytes, _ = rsa.SignPSS(rand.Reader, privkey.(*rsa.PrivateKey), crypto.SHA256, hash, nil) + default: + return nil, errors.New("Unsupported Privkey type") + } + + return &requests.RevokeDlgRequest{ + Cert: common.EncodeBase64(cert), + Signature: common.EncodeBase64(sigbytes), + }, nil +} + +func PostRevokeDlgRequest(req requests.RevokeDlgRequest, CheckerAddress string) (*requests.CheckResponse, error) { + jsonreq, err := json.Marshal(req) + if err != nil { + log.Fatal(err) + } + address := "http://" + CheckerAddress + "/RevokeDlg" + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var cResp requests.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&cResp) + log.Printf("Response: %#v\n", cResp) + + if err != nil { + return nil, err + } + return &cResp, nil +} + +func CreateReNewDlgRequest(cert *x509.Certificate, privKey interface{}) (*requests.ReNewDlgRequest, error) { + var req x509.CertificateRequest + req.DNSNames = cert.DNSNames + key, _ := privKey.(crypto.Signer) + switch key.Public().(type) { + case *rsa.PublicKey: + pubKey, _ := key.Public().(*rsa.PublicKey) + if !pubKey.Equal(cert.PublicKey){ + return nil, errors.New("Key does not match key in certificate") + } + case ed25519.PublicKey: + pubKey, _ := key.Public().(ed25519.PublicKey) + if !pubKey.Equal(cert.PublicKey){ + return nil, errors.New("Key does not match key in certificate") + } + } + + certReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &req, privKey) + if err != nil { + return nil, err + } + + return &requests.ReNewDlgRequest{ + Csr: common.EncodeBase64(certReqBytes), + }, nil +} + +func CreateKeyChangeDlgRequest(cert *x509.Certificate, privKey interface{}, newprivKey interface{}) (*requests.KeyChangeDlgRequest, error) { + var req x509.CertificateRequest + req.DNSNames = cert.DNSNames + key, _ := privKey.(crypto.Signer) + switch key.Public().(type) { + case *rsa.PublicKey: + pubKey, _ := key.Public().(*rsa.PublicKey) + if !pubKey.Equal(cert.PublicKey){ + return nil, errors.New("Old Key does not match key in certificate") + } + case ed25519.PublicKey: + pubKey, _ := key.Public().(ed25519.PublicKey) + if !pubKey.Equal(cert.PublicKey){ + return nil, errors.New("Old Key does not match key in certificate") + } + } + + certReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &req, newprivKey) + if err != nil { + return nil, err + } + + old_key_encoded, oldKeyType, err := common.EncodePublicKey(key.Public()) + if err != nil { + return nil, err + + } + + Signature, err := CreateKeyChangeSignature(certReqBytes, privKey) + if err != nil { + return nil, err + } + return &requests.KeyChangeDlgRequest{ + Csr: common.EncodeBase64(certReqBytes), + OldKeyAlg: oldKeyType, + OldKey: old_key_encoded, + Signature: Signature, + }, nil +} + +func CreateKeyChangeSignature(message []byte, privKey interface{}) (string, error){ + sigbytes := []byte{} + + switch privKey.(type) { + case ed25519.PrivateKey: + sigbytes = ed25519.Sign(privKey.(ed25519.PrivateKey), message) + case *rsa.PrivateKey: + sha256 := sha256.New() + sha256.Write(message) + hash := sha256.Sum(nil) + sigbytes, _ = rsa.SignPSS(rand.Reader, privKey.(*rsa.PrivateKey), crypto.SHA256, hash, nil) + default: + return "", errors.New("Unsupported Privkey type") + } + + return common.EncodeBase64(sigbytes), nil +} + +func CreateCheckKeyChangeDlgReq(cert []byte, privKey interface{}) (*requests.CheckKeyChangeDlgRequest, error){ + key, _ := privKey.(crypto.Signer) + old_key_encoded, oldKeyType, err := common.EncodePublicKey(key.Public()) + if err != nil { + return nil, err + + } + + Signature, err := CreateKeyChangeSignature(cert, privKey) + if err != nil { + return nil, err + } + return &requests.CheckKeyChangeDlgRequest{ + Cert: common.EncodeBase64(cert), + OldKeyAlg: oldKeyType, + OldKey: old_key_encoded, + Signature: Signature, + }, nil +} + + +func CreateCheckReNewDlgRequest(cert []byte, privkey interface{}) (*requests.CheckReNewDlgRequest, error){ + sigbytes := []byte{} + + switch privkey.(type) { + case ed25519.PrivateKey: + sigbytes = ed25519.Sign(privkey.(ed25519.PrivateKey), cert) + case *rsa.PrivateKey: + sha256 := sha256.New() + sha256.Write(cert) + hash := sha256.Sum(nil) + sigbytes, _ = rsa.SignPSS(rand.Reader, privkey.(*rsa.PrivateKey), crypto.SHA256, hash, nil) + default: + return nil, errors.New("Unsupported Privkey type") + } + + return &requests.CheckReNewDlgRequest{ + Cert: common.EncodeBase64(cert), + Signature: common.EncodeBase64(sigbytes), + }, nil +} +func PostReNewDlgRequest(req requests.ReNewDlgRequest, CAAddress string) (*requests.CAResponse, error) { + jsonreq, err := json.Marshal(req) + if err != nil { + log.Fatal(err) + } + address := "http://" + CAAddress + "/ReNewDlg" + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var caResp requests.CAResponse + err = json.NewDecoder(resp.Body).Decode(&caResp) + log.Printf("Response: %#v\n", caResp) + + if err != nil { + return nil, err + } + return &caResp, nil +} + +func PostKeyChangeDlgReq(req requests.KeyChangeDlgRequest, CAAddress string) (*requests.CAResponse, error) { + jsonreq, err := json.Marshal(req) + if err != nil { + log.Fatal(err) + } + address := "http://" + CAAddress + "/KeyChangeDlg" + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var caResp requests.CAResponse + err = json.NewDecoder(resp.Body).Decode(&caResp) + log.Printf("Response: %#v\n", caResp) + + if err != nil { + return nil, err + } + return &caResp, nil +} + +func PostCheckReNewDlgRequest(req requests.CheckReNewDlgRequest, CheckerAddress string) (*requests.CheckResponse, error) { + jsonreq, err := json.Marshal(req) + if err != nil { + log.Fatal(err) + } + address := "http://" + CheckerAddress + "/CheckReNewDlg" + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var cResp requests.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&cResp) + log.Printf("Response: %#v\n", cResp) + + if err != nil { + return nil, err + } + return &cResp, nil +} + +func PostCheckKeyChangeDlgRequest(req requests.CheckKeyChangeDlgRequest, CheckerAddress string) (*requests.CheckResponse, error) { + jsonreq, err := json.Marshal(req) + if err != nil { + log.Fatal(err) + } + address := "http://" + CheckerAddress + "/CheckKeyChangeDlg" + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var cResp requests.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&cResp) + log.Printf("Response: %#v\n", cResp) + + if err != nil { + return nil, err + } + return &cResp, nil +} + + + + diff --git a/offlineauth/cmd/RCertEncoder.go b/offlineauth/cmd/RCertEncoder.go new file mode 100755 index 00000000..d86decb6 --- /dev/null +++ b/offlineauth/cmd/RCertEncoder.go @@ -0,0 +1,55 @@ +package main + +import ( + "crypto/x509" + "encoding/hex" + "fmt" + "github.com/robinburkhard/rainsdeleg/ca" + "github.com/robinburkhard/rainsdeleg/common" + "golang.org/x/crypto/ed25519" +) + +func main() { + //certpath := os.Args[1] + //cert, _ := common.LoadCertificatePEM(certpath) + //rawcert := cert.Raw + //hexstring := hex.EncodeToString(rawcert) + //fmt.Println(":A: . [ :cert: :rhine: :zoneAuth: :noHash: "+hexstring+" ]") + + var pubkey []byte + //pubkey, _ = base64.StdEncoding.DecodeString("45lUXSSPs+zgzYIu47YiLfBv0ngwiSPZvr75l8mhr6k=") + pubkey = []byte{227, 153, 84, 93, 36, 143, 179, 236, 224, 205, 130, 46, 227, 182, 34, 45, 240, 111, 210, 120, 48, 137, 35, 217, 190, 190, 249, 151, 201, 161, 175, 169} + + var pubkeyt ed25519.PublicKey + pubkeyt = pubkey + + //pubkeyt, _, _ = ed25519.GenerateKey(rand.Reader) + //fmt.Println(reflect.TypeOf(pubkey)) + //var bytespkey interface{} + //bytespkey, _ = hex.DecodeString("e399545d248fb3ece0cd822ee3b6222df06fd278308923d9bebef997c9a1afa9") + + ca_config := ca.Config{ + PrivateKeyAlgorithm: "Ed25519", + PrivateKeyPath: "../test/testfulldata/ca.key", + CertificatePath: "../test/testfulldata/ca.cert", + RootCertsPath: "../test/testfulldata/roots/", + } + CA := ca.NewCA(ca_config) + + //var pubkey ed25519.PublicKey + //pubkey, _ = bytespkey.(ed25519.PublicKey) + + csr := x509.CertificateRequest{ + PublicKey: pubkeyt, + DNSNames: []string{"ethz.ch."}, + } + + bytecert, err := CA.IssueCertificate(&csr, true) + if err != nil { + fmt.Println(err) + } + common.StoreCertificatePEM("testrcert.pem", bytecert ) + hexstring := hex.EncodeToString(bytecert) + fmt.Println(":A: . [ :cert: :rhine: :zoneAuth: :noHash: "+hexstring+" ]") + +} diff --git a/offlineauth/cmd/ca/config/caconfig.conf b/offlineauth/cmd/ca/config/caconfig.conf new file mode 100644 index 00000000..0b858b9d --- /dev/null +++ b/offlineauth/cmd/ca/config/caconfig.conf @@ -0,0 +1,10 @@ +{ + "PrivateKeyAlgorithm": "RSA", + "PrivateKeyPath": "data/privkey.pem", + "CertificatePath": "data/cacert.pem", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "data/mappk1.pem", + "MapId": 5250323035397941290, + "ServerAddress" : "localhost:10000", + "RootCertsPath" : "roots/" +} \ No newline at end of file diff --git a/offlineauth/cmd/ca/data/cacert.pem b/offlineauth/cmd/ca/data/cacert.pem new file mode 100644 index 00000000..4257d14f --- /dev/null +++ b/offlineauth/cmd/ca/data/cacert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMDMwMjA1NjA0WhcNMjIxMDIxMjA1NjA0 +WjAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC0wPnks8OdZQkfpx+c7MPg8F2f+sm1cLINA576 +hVpvyyjQjgYZTRKicQXbmKq8bje+kIHO8zosBq58fYbQBjwq9y55eQZBLh5/S8an +IyXmOY/sFbX6KzysZ5/YD3UDdu1dZv51QhQ68k9S74K8x/P3v+p0No0wKdACuWLH +Gb9fMTGYdPAGlQ4V9hxSUEpCzkKt4pbGgKkWIcZcWOxswhGLoJ+Y/4aSBegTsVkj +maWotR70o3QkUdhYBuS0NJYfEfRnKBe38gcDfgEfW6UpQSiCaR92JeXJCaCa0Ijs +r//GHSlep6BIyJCShwjLgal/iHRlRr68+Wk3enakGSRndSPfAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIChDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQf8KIO4Q2j +Xp9YxPpodZ0gGOkS4jANBgkqhkiG9w0BAQsFAAOCAQEAPWK2Pfy5Vo5buQhJLxEK +TCe4bph5uYTDuyahbiQchPGbfmvHl0XSZ5WaQ6opyDz6/18lYOdOEt9DeAJsPb7d +c5JHm+bdi6YF/4V0Xy6wpT5r4RWokI+VjatHVzxCJ1/kup/35z14hqS6FpMM0zxu +ggcdMGGE9EJCHHsRmiEXZxZk7uGWM4/qXeBIxQTttE5KcMc2KufJEt2a/6sByDYk +kKRaXXtdI1EfFTADcjlPXlgihd+L5UyiEnzJFMgfdIz3blGz8pjuHAC9cmWqEaWP +hvuKwuy9u4JZlwGmz/4N+N5NiWdAQc0sruvC8HF0K3QG5CcMQmSxRq6wTwEzorOq +bA== +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/ca/data/mappk1.pem b/offlineauth/cmd/ca/data/mappk1.pem new file mode 100644 index 00000000..f00c39f9 --- /dev/null +++ b/offlineauth/cmd/ca/data/mappk1.pem @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaf9BMd23ERJyorU5A4LcQVbHJyFP +SU/NQjskUuSh2kEkswzeyNmfgwkgD3Wnd794cb5bru12iZygDoWzc8UkGw== +-----END PUBLIC KEY----- + diff --git a/offlineauth/cmd/ca/data/privkey.pem b/offlineauth/cmd/ca/data/privkey.pem new file mode 100644 index 00000000..85188856 --- /dev/null +++ b/offlineauth/cmd/ca/data/privkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAtMD55LPDnWUJH6cfnOzD4PBdn/rJtXCyDQOe+oVab8so0I4G +GU0SonEF25iqvG43vpCBzvM6LAaufH2G0AY8KvcueXkGQS4ef0vGpyMl5jmP7BW1 ++is8rGef2A91A3btXWb+dUIUOvJPUu+CvMfz97/qdDaNMCnQArlixxm/XzExmHTw +BpUOFfYcUlBKQs5CreKWxoCpFiHGXFjsbMIRi6CfmP+GkgXoE7FZI5mlqLUe9KN0 +JFHYWAbktDSWHxH0ZygXt/IHA34BH1ulKUEogmkfdiXlyQmgmtCI7K//xh0pXqeg +SMiQkocIy4Gpf4h0ZUa+vPlpN3p2pBkkZ3Uj3wIDAQABAoIBAGlsZFPPxTf3xeqA +Px/3uAdqKjE0xJDeufp9MixLuwOZKqT5MPVwzn2QDiqWUH62iizLe+qIUlV7UCmr +zQVnnZAxuxl+TPeXPpJgT+0Lwv8Uc6zuvMS8kxa7Ga+a1FTA+JCRkbgyYjo/OaTV +rRsORG0rskM1zgNZX8k29zXI/qU1wQZR2OMiOIK7rNsAZOP3SLSzducEUO38PwGg +MjNfKPapb4RWqnDeV+DV0h+9T0MWTBCEXL97umFTyL2WUb/kVSsgTwnvDkh3uQMF +3LWV2BwYZMxU8ifkAwWESdeIzviiasMSWg2hfa622lxQT/ssEK6Ha5wd7tkyUo+H +v9ueSIECgYEA0eElFKala77rJZUv7S6jep0rKxgddnhX+2s/jGsigsA1IsYPbD+E +W+I0ADEHMD4UVd1xcgWjUNLPdwQnJhpGx+YZXGWip+3/ZlFX2fx+o4Ul3aBW2HeS +8esloCfQ2pY89LUC1jCwgP9sQAdEUW1JAMBI4rpT+COdYOfq7sODhcMCgYEA3Hlb +AbQx4we3z+cmlFfPLxIim54hq8vikPvR+3fql8HCdVZ8fNtlF5xy03+z5glmEZc+ +/iEW8TKcMlAnDX/FI50YoRs+Yq1MBC0SQwH8nU0Xh+J+zQtywGkb253ZNUBC+4LD +xvyVkvLfkoYEQPSXdMCVhudB0ZQ7FzkOtZB0G7UCgYB1hUV3J80u5OvU0pHQlLHz +oXgfnFQ7Fy3k2WvvG7pqTmgyfYb7TSG3NZV6mfl1eP14CxRQDXoicri64vds7X++ +xUhkJYEL2UeOqnOv2yOqOo82Z2bZtTLyBYK/CCx5iXC+cXESMJdU1DFwNOF7Wt9q +7UCivETyiDbCoXo6kf3ecwKBgQC6SpBrUCcW/l6CfX5LuiaGT3yOoX8x+oTmnOFA +6oJ+2GnHW9y0Y214FemwbCdGKIrmMjY35R3NkEYK/U8CSQP6o7M77hk4p9WjcbIM +jJE3GPzZBLi/6Px9OFMhrq7qH/J5MnTannKESFRBKpxNhl6zeEbgRmeG/wkvBjc3 +k2eIQQKBgDr8CPsFf1bqTlsZf9MKE+nyt2V2uI9RMC11OKx5beohc4DBvzokhMj7 +cBBEtNMv/CJafgQEENcEh7gnA5sppAa4DLpUNZNkEONTNwmypFNIsTgap7RSy2GT +MTub/yQspM+t99Qrhq3hC2EIw1ZmhiItIDnSr2xTDLkNrQfpyq+5 +-----END RSA PRIVATE KEY----- diff --git a/offlineauth/cmd/ca/roots/cacert.pem b/offlineauth/cmd/ca/roots/cacert.pem new file mode 100644 index 00000000..4257d14f --- /dev/null +++ b/offlineauth/cmd/ca/roots/cacert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMDMwMjA1NjA0WhcNMjIxMDIxMjA1NjA0 +WjAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC0wPnks8OdZQkfpx+c7MPg8F2f+sm1cLINA576 +hVpvyyjQjgYZTRKicQXbmKq8bje+kIHO8zosBq58fYbQBjwq9y55eQZBLh5/S8an +IyXmOY/sFbX6KzysZ5/YD3UDdu1dZv51QhQ68k9S74K8x/P3v+p0No0wKdACuWLH +Gb9fMTGYdPAGlQ4V9hxSUEpCzkKt4pbGgKkWIcZcWOxswhGLoJ+Y/4aSBegTsVkj +maWotR70o3QkUdhYBuS0NJYfEfRnKBe38gcDfgEfW6UpQSiCaR92JeXJCaCa0Ijs +r//GHSlep6BIyJCShwjLgal/iHRlRr68+Wk3enakGSRndSPfAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIChDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQf8KIO4Q2j +Xp9YxPpodZ0gGOkS4jANBgkqhkiG9w0BAQsFAAOCAQEAPWK2Pfy5Vo5buQhJLxEK +TCe4bph5uYTDuyahbiQchPGbfmvHl0XSZ5WaQ6opyDz6/18lYOdOEt9DeAJsPb7d +c5JHm+bdi6YF/4V0Xy6wpT5r4RWokI+VjatHVzxCJ1/kup/35z14hqS6FpMM0zxu +ggcdMGGE9EJCHHsRmiEXZxZk7uGWM4/qXeBIxQTttE5KcMc2KufJEt2a/6sByDYk +kKRaXXtdI1EfFTADcjlPXlgihd+L5UyiEnzJFMgfdIz3blGz8pjuHAC9cmWqEaWP +hvuKwuy9u4JZlwGmz/4N+N5NiWdAQc0sruvC8HF0K3QG5CcMQmSxRq6wTwEzorOq +bA== +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/ca/run_ca.go b/offlineauth/cmd/ca/run_ca.go new file mode 100644 index 00000000..0032da09 --- /dev/null +++ b/offlineauth/cmd/ca/run_ca.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + logger15 "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/ca" + "log" + "os" +) + +func main() { + var logger = logger15.New("Module", "CA") + + var configPath string + if len(os.Args) > 1 { + configPath = os.Args[1] + } else { + configPath = "config/caconfig.conf" + } + config, err := ca.LoadConfig(configPath) + if err != nil { + log.Fatal("Error loading config: ", err) + } + myca := ca.NewCA(config) + + logger.Info(fmt.Sprintf("CA Created: %#v\n", myca)) + + myca.RunServer(myca.Address) + +} diff --git a/offlineauth/cmd/checkerExtension/config/checkerconfig.conf b/offlineauth/cmd/checkerExtension/config/checkerconfig.conf new file mode 100644 index 00000000..0850eb48 --- /dev/null +++ b/offlineauth/cmd/checkerExtension/config/checkerconfig.conf @@ -0,0 +1,10 @@ +{ + "LogID": 893878204519017005, + "LogAddress": "172.18.0.3:8090", + "LogPkeyPath": "data/logpk1.pem", + "MapID": 5250323035397941290, + "MapAddress": "172.18.0.5:8094", + "MapPkeyPath": "data/mappk1.pem", + "RootCertsPath" : "roots/", + "ServerAddress" : "localhost:10001" +} \ No newline at end of file diff --git a/offlineauth/cmd/checkerExtension/data/logpk1.pem b/offlineauth/cmd/checkerExtension/data/logpk1.pem new file mode 100644 index 00000000..eccbe11c --- /dev/null +++ b/offlineauth/cmd/checkerExtension/data/logpk1.pem @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEglmCd+uUDDXGuOxPzCCRTeGZDFaB +K4F1gAdUfJL/Kpb1G1VGrpDZJynYCtwpUkK5pY0iZ04UBwXG4LIJM9LwhQ== +-----END PUBLIC KEY----- + diff --git a/offlineauth/cmd/checkerExtension/data/mappk1.pem b/offlineauth/cmd/checkerExtension/data/mappk1.pem new file mode 100644 index 00000000..8e339de9 --- /dev/null +++ b/offlineauth/cmd/checkerExtension/data/mappk1.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaf9BMd23ERJyorU5A4LcQVbHJyFP +SU/NQjskUuSh2kEkswzeyNmfgwkgD3Wnd794cb5bru12iZygDoWzc8UkGw== +-----END PUBLIC KEY----- diff --git a/offlineauth/cmd/checkerExtension/logdata/dropped.csv b/offlineauth/cmd/checkerExtension/logdata/dropped.csv new file mode 100644 index 00000000..e69de29b diff --git a/offlineauth/cmd/checkerExtension/logdata/invalid.gob b/offlineauth/cmd/checkerExtension/logdata/invalid.gob new file mode 100644 index 00000000..bcf95548 Binary files /dev/null and b/offlineauth/cmd/checkerExtension/logdata/invalid.gob differ diff --git a/offlineauth/cmd/checkerExtension/logdata/valid.gob b/offlineauth/cmd/checkerExtension/logdata/valid.gob new file mode 100644 index 00000000..b87ddb35 Binary files /dev/null and b/offlineauth/cmd/checkerExtension/logdata/valid.gob differ diff --git a/offlineauth/cmd/checkerExtension/roots/cacert.pem b/offlineauth/cmd/checkerExtension/roots/cacert.pem new file mode 100644 index 00000000..4257d14f --- /dev/null +++ b/offlineauth/cmd/checkerExtension/roots/cacert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMDMwMjA1NjA0WhcNMjIxMDIxMjA1NjA0 +WjAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC0wPnks8OdZQkfpx+c7MPg8F2f+sm1cLINA576 +hVpvyyjQjgYZTRKicQXbmKq8bje+kIHO8zosBq58fYbQBjwq9y55eQZBLh5/S8an +IyXmOY/sFbX6KzysZ5/YD3UDdu1dZv51QhQ68k9S74K8x/P3v+p0No0wKdACuWLH +Gb9fMTGYdPAGlQ4V9hxSUEpCzkKt4pbGgKkWIcZcWOxswhGLoJ+Y/4aSBegTsVkj +maWotR70o3QkUdhYBuS0NJYfEfRnKBe38gcDfgEfW6UpQSiCaR92JeXJCaCa0Ijs +r//GHSlep6BIyJCShwjLgal/iHRlRr68+Wk3enakGSRndSPfAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIChDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQf8KIO4Q2j +Xp9YxPpodZ0gGOkS4jANBgkqhkiG9w0BAQsFAAOCAQEAPWK2Pfy5Vo5buQhJLxEK +TCe4bph5uYTDuyahbiQchPGbfmvHl0XSZ5WaQ6opyDz6/18lYOdOEt9DeAJsPb7d +c5JHm+bdi6YF/4V0Xy6wpT5r4RWokI+VjatHVzxCJ1/kup/35z14hqS6FpMM0zxu +ggcdMGGE9EJCHHsRmiEXZxZk7uGWM4/qXeBIxQTttE5KcMc2KufJEt2a/6sByDYk +kKRaXXtdI1EfFTADcjlPXlgihd+L5UyiEnzJFMgfdIz3blGz8pjuHAC9cmWqEaWP +hvuKwuy9u4JZlwGmz/4N+N5NiWdAQc0sruvC8HF0K3QG5CcMQmSxRq6wTwEzorOq +bA== +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/checkerExtension/run_checker.go b/offlineauth/cmd/checkerExtension/run_checker.go new file mode 100644 index 00000000..ba92207b --- /dev/null +++ b/offlineauth/cmd/checkerExtension/run_checker.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + logger15 "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/checkerExtension" + "log" + "os" +) + +func main() { + var logger = logger15.New("Module", "CheckerExtension") + + var configPath string + if len(os.Args) > 1 { + configPath = os.Args[1] + } else { + configPath = "config/checkerconfig.conf" + } + config, err := checkerExtension.LoadConfig(configPath) + if err != nil { + log.Fatal("Error loading config: ", err) + } + + checker := checkerExtension.NewChecker(config) + logger.Info(fmt.Sprintf("Checker Created: %#v\n", checker)) + + checker.RunServer(checker.Address) +} diff --git a/offlineauth/cmd/checkerExtension/trillian/lastIdx b/offlineauth/cmd/checkerExtension/trillian/lastIdx new file mode 100644 index 00000000..7813681f --- /dev/null +++ b/offlineauth/cmd/checkerExtension/trillian/lastIdx @@ -0,0 +1 @@ +5 \ No newline at end of file diff --git a/offlineauth/cmd/child/data/Ed25519.sec b/offlineauth/cmd/child/data/Ed25519.sec new file mode 100644 index 00000000..c8816178 Binary files /dev/null and b/offlineauth/cmd/child/data/Ed25519.sec differ diff --git a/offlineauth/cmd/child/data/ReNewedCert.pem b/offlineauth/cmd/child/data/ReNewedCert.pem new file mode 100644 index 00000000..6b3b2688 --- /dev/null +++ b/offlineauth/cmd/child/data/ReNewedCert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2DCBwaADAgECAgEAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFVJBSU5T +IEVYQU1QTEUgUk9PVCBDQTAeFw0yMTEwMzEyMTQzNTdaFw0yMjEwMjIyMTQzNTda +MAAwKjAFBgMrZXADIQBqAwAjCFEoVEywS5oqBClf7gD6ObHOwhfMKaAEvuhmFqM4 +MDYwHwYDVR0jBBgwFoAUH/CiDuENo16fWMT6aHWdIBjpEuIwEwYDVR0RAQH/BAkw +B4IFaGkuY2gwDQYJKoZIhvcNAQELBQADggEBACVbTQfOqpQlyS4nEG1qAxwpcuZj +hu0cHx+dzlNNAud/FPLvQk2iymSusbSwXJ1U5TfeQmgVgvFmu8LoT7QGGlCLid4G +bmRsg5VSEvBRccJ47K2vAoXsbEDu7Z7lo0VIWILQm7SnGQpwUpsZ+1RZ7TJUm9qk +bJk/EdCYFrBI6zxydyJgqYnkpBjcKkRNqcr78elV0cJt+5dDERQeS8UPo8azoMZ7 +B0xecBS7aWMKVMF9UXpnC8YTp/kYUKIkCyKt3Ox80DyRcu+vO1mGOAAlodBIS5jt +wG12Z2thVKKqXn4Srlg2RFgLaZlueknVjCUY/4ArK52dOKvuLVCxI1sM/Rs= +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/child/data/cert.pem b/offlineauth/cmd/child/data/cert.pem new file mode 100644 index 00000000..b88abdd8 --- /dev/null +++ b/offlineauth/cmd/child/data/cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB3DCBxaADAgECAgEAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFVJBSU5T +IEVYQU1QTEUgUk9PVCBDQTAeFw0yMTEwMzEwMzI3MDNaFw0yMjEwMjIwMzI3MDNa +MAAwKjAFBgMrZXADIQBqAwAjCFEoVEywS5oqBClf7gD6ObHOwhfMKaAEvuhmFqM8 +MDowHwYDVR0jBBgwFoAUH/CiDuENo16fWMT6aHWdIBjpEuIwFwYDVR0RAQH/BA0w +C4IJYmxhYmxhLmNoMA0GCSqGSIb3DQEBCwUAA4IBAQAOTJwUbHv8bSAisHjp2CIY +7QDHRSSZ0aXpcwDueKh5odUa2jUZ5NyC5jArYYRalAf2Op5bQ2pgE5oiJ6PYaEJv +efQty6JrbUBq48gtJnqPRRHLiCC1yQSxXWEMNA2JYPDpbxhH9DYvY2fSP5ZUWVvg +1Fw3DNOVMVRmW7zQ6KKAVDG6ZySDDeC2ZMsHpaZ5wVkFVXiupVAhNZvBB4yehQYq +Yd+X93UFyCUcoW5Z1yY1JugmYjrMB1IL7kpMHbdAkk+Sqrmpa3Jp/ZIBPqEOjDZ7 +xoiA+/A68OcM6O/iLLuaVBKZ8Dni6XFmCyzl4SADlKnqSWTVNYnXSB56FQxjjBEx +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/child/data/csr.pem b/offlineauth/cmd/child/data/csr.pem new file mode 100644 index 00000000..6c9d4fa2 --- /dev/null +++ b/offlineauth/cmd/child/data/csr.pem @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIGiMFYCAQAwADAqMAUGAytlcAMhAGoDACMIUShUTLBLmioEKV/uAPo5sc7CF8wp +oAS+6GYWoCMwIQYJKoZIhvcNAQkOMRQwEjAQBgNVHREECTAHggVoaS5jaDAFBgMr +ZXADQQAXXvyJo4Y8Y2h4PrdCdqybXWUW+JnGspUDVG6oEnvleLOWrFCOIHIqMFPy +kliTg9KdTc2Y1orMX8P2y1c6jLUJ +-----END CERTIFICATE REQUEST----- diff --git a/offlineauth/cmd/child/run_child.go b/offlineauth/cmd/child/run_child.go new file mode 100644 index 00000000..fd3b6f46 --- /dev/null +++ b/offlineauth/cmd/child/run_child.go @@ -0,0 +1,315 @@ +package main + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "github.com/robinburkhard/rainsdeleg/child" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/spf13/cobra" + "log" +) + +var privKeyType string +var privKeyRSA *rsa.PrivateKey +var privKeyEd25519 ed25519.PrivateKey +var privKey interface{} +var newprivKey interface{} +var outputPath string +var zone string +var CA string +var CAAddress string +var CheckerAddress string +var Cert *x509.Certificate + +var rootCmd = &cobra.Command{ + Use: "run_child", + Short: "Child Zone Manager for Rains Delegation Service", + Long: "Child Zone Manager for Rains Delegation Service: Creates CSRs for NewDlg requests and runs ReNewDlg requests for existing certificates", +} + + +var NewDlgCmd = &cobra.Command{ + Example: "./run_child NewDlg Ed25519 path/to/key/example.key", + Use: "NewDlg [PrivateKey Type] [PrivateKey Path]", + Short: "Create CSR for a New Delegation", + Long: "PrivateKey Type has to be \"RSA\" or \"Ed25519\"", + Args: nil, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 2 { + var err error + switch args[0] { + case "RSA": + privKey, err = common.LoadRSAPrivateKeyPEM(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + case "Ed25519": + privKey, err = common.LoadPrivateKeyEd25519(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + default: + log.Fatalf("Unsupported key type: %s (must be RSA or Ed25519)", args[0]) + } + } else if len(args) == 1 { + switch args[0] { + case "RSA": + privKey, _ = rsa.GenerateKey(rand.Reader, 2048) + case "Ed25519": + _, privKey, _ = ed25519.GenerateKey(rand.Reader) + default: + log.Fatalf("Unsupported key type: %s (must be RSA or Ed25519)", args[0]) + } + } else { + cmd.Help() + return + } + + csrbytes, err := child.CreateCSR(zone, CA, privKey) + if err != nil { + log.Fatal("Error creating CSR: ", err) + } + + var fileName string + parsedcsr, _ := x509.ParseCertificateRequest(csrbytes) + if parsedcsr != nil { + fileName = parsedcsr.DNSNames[0] + "_Csr.pem" + } + + var outDir string + + if outputPath[len(outputPath)-1:] == "/" { + outDir = outputPath + fileName + } else { + outDir = outputPath + "/" + fileName + } + + err = common.StoreCertificateRequestPEM(outDir, csrbytes) + if err != nil { + log.Fatal("Error storing CSR: ", err) + } + + log.Println("CSR for NewDlg created") + }, +} + +var ReNewDlgCmd = &cobra.Command{ + Use: "ReNewDlg [PrivateKey Type] [PrivateKey Path] [Cert Path]", + Short: "Renew an existing Certificate you control", + Long: "PrivateKey Type has to be \"RSA\" or \"Ed25519\"", + Args: nil, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 3 { + var err error + switch args[0] { + case "RSA": + privKey, err = common.LoadRSAPrivateKeyPEM(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + case "Ed25519": + privKey, err = common.LoadPrivateKeyEd25519(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + default: + log.Fatalf("Unsupported key type: %s (must be RSA or Ed25519)", args[0]) + } + + Cert, err = common.LoadCertificatePEM(args[2]) + if err != nil { + log.Fatal(err) + } + + } else { + cmd.Help() + return + } + + certbytes, err := child.ReNewDlg(Cert, privKey, CAAddress, CheckerAddress) + if err != nil { + log.Fatal(err) + } + + var fileName string + parsedcsr, _ := x509.ParseCertificate(certbytes) + if parsedcsr != nil { + fileName = parsedcsr.DNSNames[0] + "_Cert_New.pem" + } + + var outDir string + + if outputPath[len(outputPath)-1:] == "/" { + outDir = outputPath + fileName + } else { + outDir = outputPath + "/" + fileName + } + + common.StoreCertificatePEM(outDir, certbytes) + + log.Println("Re-Newed Certificate stored") + + return + }, +} + +var KeyChangeDlgCmd = &cobra.Command{ + Use: "KeyChangeDlg [PrivateKey Type] [PrivateKey Path] [NewPrivateKey Type] [NewPrivateKey Path] [Cert Path] ", + Short: "Renew an existing Certificate you control and change keys", + Long: "PrivateKey Type has to be \"RSA\" or \"Ed25519\"", + Args: nil, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 5 { + var err error + switch args[0] { + case "RSA": + privKey, err = common.LoadRSAPrivateKeyPEM(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + case "Ed25519": + privKey, err = common.LoadPrivateKeyEd25519(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + default: + log.Fatalf("Unsupported key type: %s (must be RSA or Ed25519)", args[0]) + } + + switch args[2] { + case "RSA": + newprivKey, err = common.LoadRSAPrivateKeyPEM(args[3]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + case "Ed25519": + newprivKey, err = common.LoadPrivateKeyEd25519(args[3]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + default: + log.Fatalf("Unsupported new key type: %s (must be RSA or Ed25519)", args[2]) + } + + Cert, err = common.LoadCertificatePEM(args[4]) + if err != nil { + log.Fatal(err) + } + + } else { + cmd.Help() + return + } + + certbytes, err := child.KeyChangeDlg(Cert, privKey, newprivKey, CAAddress, CheckerAddress) + if err != nil { + log.Fatal(err) + } + + var fileName string + parsedcsr, _ := x509.ParseCertificate(certbytes) + if parsedcsr != nil { + fileName = parsedcsr.DNSNames[0] + "_Cert_NewKey.pem" + } + + var outDir string + + if outputPath[len(outputPath)-1:] == "/" { + outDir = outputPath + fileName + } else { + outDir = outputPath + "/" + fileName + } + + common.StoreCertificatePEM(outDir, certbytes) + + log.Println("Re-Newed Certificate stored") + + return + }, +} + + +var RevokeDlgCmd = &cobra.Command{ + Use: "RevokeDlg [PrivateKey Type] [PrivateKey Path] [Cert Path]", + Short: "Revoke an existing Certificate you control", + Long: "PrivateKey Type has to be \"RSA\" or \"Ed25519\"", + Args: nil, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 3 { + var err error + switch args[0] { + case "RSA": + privKey, err = common.LoadRSAPrivateKeyPEM(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + case "Ed25519": + privKey, err = common.LoadPrivateKeyEd25519(args[1]) + if err != nil { + log.Fatal("Error loading private key: ", err) + } + default: + log.Fatalf("Unsupported key type: %s (must be RSA or Ed25519)", args[0]) + } + + Cert, err = common.LoadCertificatePEM(args[2]) + if err != nil { + log.Fatal(err) + } + + } else { + cmd.Help() + return + } + + err := child.RevokeDlg(Cert, privKey, CheckerAddress) + if err != nil { + log.Fatal(err) + } + + log.Println("Certificate Revoked") + + return + }, +} + +func init() { + + NewDlgCmd.Flags().StringVar(&outputPath, "out", "./", "Output Folder") + NewDlgCmd.Flags().StringVar(&zone, "zone", "", "Zone for Certificate") + NewDlgCmd.Flags().StringVar(&CA, "CA", "Example RAINS CA", "CA Name") + NewDlgCmd.MarkFlagDirname("out") + NewDlgCmd.MarkFlagRequired("zone") + + ReNewDlgCmd.Flags().StringVar(&outputPath, "out", "./", "Output Folder") + ReNewDlgCmd.Flags().StringVar(&CA, "CA", "Same as existing Cert", "CA Name") + ReNewDlgCmd.MarkFlagDirname("out") + ReNewDlgCmd.Flags().StringVar(&CAAddress, "CaAddr", "localhost:10000", "CA Address") + ReNewDlgCmd.Flags().StringVar(&CheckerAddress, "CheckerAddr", "localhost:10001", "Checker Address") + + KeyChangeDlgCmd.Flags().StringVar(&outputPath, "out", "./", "Output Folder") + KeyChangeDlgCmd.Flags().StringVar(&CA, "CA", "Same as existing Cert", "CA Name") + KeyChangeDlgCmd.MarkFlagDirname("out") + KeyChangeDlgCmd.Flags().StringVar(&CAAddress, "CaAddr", "localhost:10000", "CA Address") + KeyChangeDlgCmd.Flags().StringVar(&CheckerAddress, "CheckerAddr", "localhost:10001", "Checker Address") + + RevokeDlgCmd.Flags().StringVar(&CheckerAddress, "CheckerAddr", "localhost:10001", "Checker Address") + + +} +func main() { + rootCmd.AddCommand(NewDlgCmd) + rootCmd.AddCommand(ReNewDlgCmd) + rootCmd.AddCommand(KeyChangeDlgCmd) + rootCmd.AddCommand(RevokeDlgCmd) + err := rootCmd.Execute() + if err != nil { + log.Fatal(err) + } + return + +} + + diff --git a/offlineauth/cmd/keyManager/certGen.go b/offlineauth/cmd/keyManager/certGen.go new file mode 100644 index 00000000..1ed5e5fd --- /dev/null +++ b/offlineauth/cmd/keyManager/certGen.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "github.com/robinburkhard/rainsdeleg/keyManager" + "log" + "os" +) + +func main() { + fmt.Println("INSTRUCTIONS: ./certGen [KeyType] [PrivateKeyPath] [CertificatePath]\tKeyType = RSA or Ed25519\tPrivateKeyPath = e.g keys/private.pem\tCertificatePath = e.g certs/cert.pem") + if len(os.Args) != 4 { + log.Fatal("Not enough arguments") + } + + if os.Args[1] != "RSA" && os.Args[1] != "Ed25519" { + log.Fatal("Unsupported Algorithm") + } + + err := keyManager.CreateSelfSignedCACertificate(os.Args[1], os.Args[2], os.Args[3]) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Certificate stored") + +} \ No newline at end of file diff --git a/offlineauth/cmd/keyManager/keyGen.go b/offlineauth/cmd/keyManager/keyGen.go new file mode 100644 index 00000000..999780b5 --- /dev/null +++ b/offlineauth/cmd/keyManager/keyGen.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "github.com/robinburkhard/rainsdeleg/keyManager" + "log" + "os" +) + +func main() { + fmt.Println("INSTRUCTIONS: ./keyGen [KeyType] [OutputPath]\tKeyType = RSA or Ed25519\tOutputPath = e.g keys/private.pem") + + if len(os.Args) != 3 { + log.Fatal("Not enough arguments") + } + + switch os.Args[1] { + case "RSA": + err := keyManager.CreateRSAKey(os.Args[2]) + if err != nil { + log.Fatal(err) + } + case "Ed25519": + err := keyManager.CreateEd25519Key(os.Args[2]) + if err != nil { + log.Fatal(err) + } + default: + log.Fatal("Unsupported Algorithm") + } + + fmt.Println("Key stored") + +} diff --git a/offlineauth/cmd/parent/config/parentconfig.conf b/offlineauth/cmd/parent/config/parentconfig.conf new file mode 100644 index 00000000..f474f927 --- /dev/null +++ b/offlineauth/cmd/parent/config/parentconfig.conf @@ -0,0 +1,10 @@ +{ + "Zone": "ch", + "AuthenticationType": "certificate", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "data/chEd25519.sec", + "CertificatePath": "data/chcert.pem", + "LogCheckerExtAddress": "localhost:10001", + "CAAddress": "localhost:10000", + "OutputDir": "output/" +} \ No newline at end of file diff --git a/offlineauth/cmd/parent/data/chEd25519.sec b/offlineauth/cmd/parent/data/chEd25519.sec new file mode 100644 index 00000000..ba8a9c60 --- /dev/null +++ b/offlineauth/cmd/parent/data/chEd25519.sec @@ -0,0 +1 @@ +^,85ހL**(;έ@p7 xci@'[j@!]ͼ \ No newline at end of file diff --git a/offlineauth/cmd/parent/data/chcert.pem b/offlineauth/cmd/parent/data/chcert.pem new file mode 100644 index 00000000..d346e4f1 --- /dev/null +++ b/offlineauth/cmd/parent/data/chcert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB1TCBvqADAgECAgEAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFVJBSU5T +IEVYQU1QTEUgUk9PVCBDQTAeFw0yMTEwMzAyMTE5NTRaFw0yMjEwMjEyMTE5NTRa +MAAwKjAFBgMrZXADIQCHcDcN3MnzhtJ462NpQPgnW4VqQJO5FN3EIfxdEM288aM1 +MDMwHwYDVR0jBBgwFoAUH/CiDuENo16fWMT6aHWdIBjpEuIwEAYDVR0RAQH/BAYw +BIICY2gwDQYJKoZIhvcNAQELBQADggEBAG8S4h+HNqR6aFdiUIBQe3nqyAlHy2lA +6dJWr+WOYXfb/ujggIuVydulbGC2WNqYVRD5D5BacIrD6HwdpZHlaJV+ovSM6O9O +yd7SGZV+hKYngNdzIvyv+0hcw3bm3qT3egOtWcsrs+fVdz5NB0LQaUbQuwXaBu/B +dWB4Efm/dOWrK9qBQkIs1pnzniF9Z1M5fzCz3K8fUoKTvP4hT1o9FOy/hzJHZ7+d +IO/zGmMwrnwcW83ewqV9b1Ud4OGO8ucNC642ywcY6m7/g5jX1BVc4RX0ZzfHftLf +sfhukPUfr6VujNbNzChQgS5PgGrkpg1d/u1KN2UCDqYDgtYRUKlh2Mk= +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/parent/output/cert.pem b/offlineauth/cmd/parent/output/cert.pem new file mode 100644 index 00000000..546805a3 --- /dev/null +++ b/offlineauth/cmd/parent/output/cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2DCBwaADAgECAgEAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFVJBSU5T +IEVYQU1QTEUgUk9PVCBDQTAeFw0yMTEwMzEyMTQzMzBaFw0yMjEwMjIyMTQzMzBa +MAAwKjAFBgMrZXADIQBqAwAjCFEoVEywS5oqBClf7gD6ObHOwhfMKaAEvuhmFqM4 +MDYwHwYDVR0jBBgwFoAUH/CiDuENo16fWMT6aHWdIBjpEuIwEwYDVR0RAQH/BAkw +B4IFaGkuY2gwDQYJKoZIhvcNAQELBQADggEBAC07LbU6lAyDneIrcArV/GzlBDfc +Pn/aVfg3YM3jr8bvpSZZy3L5zs65dWDxAhE8n9gb5f9xz7Sg9eKsYDSJNyohYB4z +6GQHkYTRYHXkGU/xnHMFn7sbvM15NGtRIUGAMzf9TNiQxDo+P8OA3eWiOsYlHsIL +L5JzOuiDHC1JbSEMHsMdIIHmEEh+nqDBMI/1hyrmvSzDt6PTFo8EPS8/td02el8L +cdS+MFx602A5ELTKlUPADFxzJz6PzKrtAZQm8bZU3VMMuJjFUzYKfTXBOO1WGTd5 +5G7l9KlIrh9twXGU3HaYviIKq3lkFKfaizq3sOluYBepN5wP2LkdSX/aBfM= +-----END CERTIFICATE----- diff --git a/offlineauth/cmd/parent/run_parent.go b/offlineauth/cmd/parent/run_parent.go new file mode 100644 index 00000000..7904b866 --- /dev/null +++ b/offlineauth/cmd/parent/run_parent.go @@ -0,0 +1,86 @@ +package main + +import ( + "crypto/x509" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/parent" + "github.com/spf13/cobra" + "log" +) + + +var config parent.Config +var csrPath string +var IndependentSubZone bool + +var rootCmd = &cobra.Command{ + Use: "run_parent [Config Path]", + Short: "Parent Zone Manager for Rains Delegation Service", + Long: "Parent Zone Manager for Rains Delegation Service: Runs NewDlg request for CSR", + Args: nil, + Run: func(cmd *cobra.Command, args []string) { + var err error + var configpath string + if len(args) == 1 { + configpath = args[0] + } else { + configpath = "config/parentconfig.conf" + } + config, err = parent.LoadConfig(configpath) + if err != nil { + cmd.Help() + log.Fatalf("Was not able to load config file: %v", err) + } + }, +} + +func init() { + rootCmd.Flags().StringVar(&csrPath, "NewDlg", "", "CSR Path") + rootCmd.Flags().BoolVar(&IndependentSubZone, "IndSubZone", true, "Independent Subzone Flag") +} +func main() { + + err := rootCmd.Execute() + if err != nil { + log.Fatal(err) + } + par := parent.NewParent(config) + + log.Printf("Parent Created: %#v\n", par) + + if rootCmd.Flag("NewDlg").Changed { + csrbytes, err := common.LoadCertificateRequestPEM(csrPath) + if err != nil { + log.Fatal("Could not load CSR from "+csrPath+" ", err) + } + + certbytes, err := par.NewDlg(csrbytes, IndependentSubZone) + if err != nil { + log.Fatal(err) + } + //fmt.Println(certbytes) + var fileName string + parsedcert, _ := x509.ParseCertificate(certbytes) + if parsedcert != nil { + fileName = parsedcert.DNSNames[0] + "_Cert.pem" + } + + var outDir string + + if par.OutputDir[len(par.OutputDir)-1:] == "/" { + outDir = par.OutputDir + fileName + } else { + outDir = par.OutputDir + "/" + fileName + } + + common.StoreCertificatePEM(outDir, certbytes) + log.Println("Parent: Certificate Stored") + + return + } + + + log.Println("No Flags set:") + rootCmd.Help() + +} diff --git a/offlineauth/cmd/testrcert.pem b/offlineauth/cmd/testrcert.pem new file mode 100644 index 00000000..4dcac9d0 --- /dev/null +++ b/offlineauth/cmd/testrcert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBMTCB5KADAgECAgF7MAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDIyMjIwNTUzOFoXDTIzMDIxMzIwNTUzOFowADAqMAUGAytlcAMh +AOOZVF0kj7Ps4M2CLuO2Ii3wb9J4MIkj2b6++ZfJoa+po2gwZjAOBgNVHQ8BAf8E +BAMCB4AwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRdwkfb0TZ6BS5J2EkWjL+Q +lAOVzDAWBgNVHREBAf8EDDAKgghldGh6LmNoLjANBgQrg3QJBAUwAwEB/zAFBgMr +ZXADQQBnRhdP7h3pGdWl393gyIvPGVRmH39vZhidnx4Y06xk4JzhCG7Kn7iqJlcw +gAIFgGpXx0CKFqzY2/Q9xoV2Z4MG +-----END CERTIFICATE----- diff --git a/offlineauth/common/dnsutil.go b/offlineauth/common/dnsutil.go new file mode 100644 index 00000000..eecafbf1 --- /dev/null +++ b/offlineauth/common/dnsutil.go @@ -0,0 +1,64 @@ +package common + +import ( + "crypto/ed25519" + "crypto/rsa" + "errors" + "github.com/miekg/dns" +) + +func QueryDNSKeyRSA(zone string) (*rsa.PublicKey, error) { + m := new(dns.Msg) + m.SetEdns0(4096, true) + m.SetQuestion(zone, dns.TypeDNSKEY) + + c := new(dns.Client) + in, _, err := c.Exchange(m, "8.8.8.8:53") + if err != nil { + return nil, err + } + for _, rr := range in.Answer { + dnskey, ok := rr.(*dns.DNSKEY) + if !ok { + continue + } + // 257 = Key Signing Key , 256 = Zone Signing Key + if !(dnskey.Flags == 257){ + continue + } + if !(dnskey.Algorithm == dns.RSASHA1 || dnskey.Algorithm == dns.RSASHA256 || dnskey.Algorithm == dns.RSASHA512 ){ + continue + } + + return dnskey.PublicKeyRSA(), nil + } + return nil, errors.New("DNSKEY: Key not found") +} + +func QueryDNSKeyEd25519(zone string) (ed25519.PublicKey, error) { + m := new(dns.Msg) + m.SetEdns0(4096, true) + m.SetQuestion(zone, dns.TypeDNSKEY) + + c := new(dns.Client) + in, _, err := c.Exchange(m, "8.8.8.8:53") + if err != nil { + return nil, err + } + for _, rr := range in.Answer { + dnskey, ok := rr.(*dns.DNSKEY) + if !ok { + continue + } + if !(dnskey.Flags == 257){ + continue + } + if !(dnskey.Algorithm == dns.ED25519 ){ + continue + } + + return dnskey.PublicKeyED25519(), nil + } + return nil, errors.New("DNSKEY: Key not found") +} + diff --git a/offlineauth/common/util.go b/offlineauth/common/util.go new file mode 100644 index 00000000..9020f5ee --- /dev/null +++ b/offlineauth/common/util.go @@ -0,0 +1,317 @@ +package common + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "log" + "math/big" + "os" + "strings" + "time" +) + +func StoreCertificateRequestPEM(path string, csr []byte) error { + file, err := os.Create(path) + if err != nil { + return err + } + + pemcert := pem.Block{ + Type: "CERTIFICATE REQUEST", + Headers: nil, + Bytes: csr, + } + + err = pem.Encode(file, &pemcert) + if err != nil { + return err + } + file.Close() + return nil +} + +func LoadCertificateRequestPEM(path string) ([]byte, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + block, _ := pem.Decode(bytes) + + return block.Bytes, nil +} + +func StoreCertificatePEM(path string, cert []byte) error { + file, err := os.Create(path) + if err != nil { + return err + } + + pemcert := pem.Block{ + Type: "CERTIFICATE", + Headers: nil, + Bytes: cert, + } + + err = pem.Encode(file, &pemcert) + if err != nil { + return err + } + file.Close() + return nil +} + +func LoadCertificatePEM(path string) (*x509.Certificate, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + block, _ := pem.Decode(bytes) + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + return cert, nil +} +func StorePrivateKeyEd25519(path string, key ed25519.PrivateKey) error { + file, err := os.Create(path) + if err != nil { + log.Println(err) + } + + privKey := pem.Block{ + Type: "RAINS Ed25519 PRIVATE KEY", + Headers: nil, + Bytes: key, + } + + err = pem.Encode(file, &privKey) + if err != nil { + log.Println(err) + } + file.Close() + return nil +} + +func LoadPrivateKeyEd25519(path string) (ed25519.PrivateKey, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + block, _ := pem.Decode(bytes) + + privKey := block.Bytes + if err != nil { + return nil, err + } + + return privKey, nil + +} + +func StoreRSAPrivateKeyPEM(key *rsa.PrivateKey, path string) error{ + file, err := os.Create(path) + if err != nil { + return err + } + + privKey := pem.Block{ + Type: "RSA PRIVATE KEY", + Headers: nil, + Bytes: x509.MarshalPKCS1PrivateKey(key), + } + + err = pem.Encode(file, &privKey) + if err != nil { + return err + } + file.Close() + return nil +} + +func LoadRSAPrivateKeyPEM(path string) (*rsa.PrivateKey, error) { + + bytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + block, _ := pem.Decode(bytes) + + privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + return privKey, nil + +} + +func PublicKeyToStringPEM(key interface{}) (string, error) { + + switch key.(type) { + case *rsa.PublicKey: + pubKey := pem.Block{ + Type: "RSA PUBLIC KEY", + Headers: nil, + Bytes: x509.MarshalPKCS1PublicKey(key.(*rsa.PublicKey)), + } + + return string(pem.EncodeToMemory(&pubKey)), nil + + case *ed25519.PublicKey: + bytes, err := x509.MarshalPKIXPublicKey(*key.(*ed25519.PublicKey)) + if err != nil { + fmt.Println(err) + } + pubKey := pem.Block{ + Type: "PUBLIC KEY", + Headers: nil, + Bytes: bytes, + } + + return string(pem.EncodeToMemory(&pubKey)), nil + + default: + return "", errors.New("unsupported key") + } + +} + +func PublicKeyFromStringPEM(key string) (interface{}, error) { + + block, _ := pem.Decode([]byte(key)) + + if block.Type == "RSA PUBLIC KEY" { + pubKey, _ := x509.ParsePKCS1PublicKey(block.Bytes) + return pubKey, nil + + } else if block.Type == "PUBLIC KEY" { + pubKey, _ := x509.ParsePKIXPublicKey(block.Bytes) + return pubKey, nil + + } else { + return nil, errors.New("unsupported key") + } + +} + +func EncodePublicKey(key interface{}) (string, string, error) { + switch key.(type) { + case *rsa.PublicKey: + keybytes := x509.MarshalPKCS1PublicKey(key.(*rsa.PublicKey)) + return EncodeBase64(keybytes), "RSA", nil + + case *ed25519.PublicKey: + keybytes, err := x509.MarshalPKIXPublicKey(*key.(*ed25519.PublicKey)) + if err != nil { + return "", "", err + } + return EncodeBase64(keybytes), "Ed25519", nil + case ed25519.PublicKey: + keybytes, err := x509.MarshalPKIXPublicKey(key) + if err != nil { + return "", "", err + } + return EncodeBase64(keybytes), "Ed25519", nil + + default: + return "", "", errors.New("unsupported key") + } +} + +func DecodePublicKey(key string, alg string) (interface{}, error) { + fmt.Println(key, alg) + decodedKey, err := DecodeBase64(key) + if err != nil { + return nil, err + } + switch alg { + case "RSA": + pubKey, err := x509.ParsePKCS1PublicKey(decodedKey) + if err != nil { + return nil, err + } + return pubKey, nil + + case "Ed25519": + pubKey, err := x509.ParsePKIXPublicKey(decodedKey) + if err != nil { + return nil, err + } + if _, ok := pubKey.(ed25519.PublicKey); ok { + return pubKey.(ed25519.PublicKey), nil + } else { + return "", errors.New("public key type / alg type mismatch") + } + + default: + return "", errors.New("unsupported alg") + } +} + +func CreateSelfSignedCert(pubkey interface{}, privkey interface{}, domain string) ([]byte, error) { + if _, ok := pubkey.(*ed25519.PublicKey); ok { + pubkey = *pubkey.(*ed25519.PublicKey) + } + var req x509.Certificate + req.DNSNames = append(req.DNSNames, domain) + req.SerialNumber = big.NewInt(1) + req.NotBefore = time.Now() + req.NotAfter = time.Now().Add(time.Hour) + certbytes, err := x509.CreateCertificate(rand.Reader, &req, &req, pubkey, privkey) + if err != nil { + log.Println("error creating self signed cert", err) + } + + return certbytes, err +} + +func CreateSelfSignedCertCA(pubkey interface{}, privkey interface{}) ([]byte, error) { + if _, ok := pubkey.(*ed25519.PublicKey); ok { + pubkey = *pubkey.(*ed25519.PublicKey) + } + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "RHINE EXAMPLE CA"}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 356), + BasicConstraintsValid: true, + IsCA: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + } + + certbytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pubkey, privkey) + if err != nil { + log.Println("error creating self signed cert", err) + } + return certbytes, err +} + +func EncodeBase64(bytes []byte) string { + return base64.RawURLEncoding.EncodeToString(bytes) +} + +func DecodeBase64(data string) ([]byte, error) { + bytes, err := base64.RawURLEncoding.DecodeString(data) + return bytes, err +} + +func GetParentZone(subzone string) string { + split := strings.SplitN(subzone, ".", 2) + if len(split) > 1 { + return split[1] + } else { + return "" + } + +} + diff --git a/offlineauth/common/util_test.go b/offlineauth/common/util_test.go new file mode 100644 index 00000000..0f0ba9d5 --- /dev/null +++ b/offlineauth/common/util_test.go @@ -0,0 +1,100 @@ +package common + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "fmt" + "reflect" + "testing" +) + +func TestLoadAndStoreFile(t *testing.T) { + + originalKey, _ := rsa.GenerateKey(rand.Reader, 2048) + + StoreRSAPrivateKeyPEM(originalKey, "testdata/testkey.pem") + + loadedKey, _ := LoadRSAPrivateKeyPEM("testdata/testkey.pem") + + if !originalKey.Equal(loadedKey) { + t.Errorf("store and load failed") + } +} + +func TestStringPEMRSA(t *testing.T) { + + originalKey, _ := rsa.GenerateKey(rand.Reader, 2048) + + pubkey := originalKey.PublicKey + + stringKey, _ := PublicKeyToStringPEM(&pubkey) + + fmt.Println(stringKey) + + parsedKey, _ := PublicKeyFromStringPEM(stringKey) + + if !pubkey.Equal(parsedKey) { + t.Errorf("string convert and parse failed (RSA)") + } + +} +func TestStringPEMEd25519(t *testing.T) { + + pubkey, _, _ := ed25519.GenerateKey(rand.Reader) + + stringKey, _ := PublicKeyToStringPEM(&pubkey) + + fmt.Println(stringKey) + + parsedKey, _ := PublicKeyFromStringPEM(stringKey) + + if !pubkey.Equal(parsedKey) { + t.Errorf("string convert and parse failed (Ed25519)") + } + +} + +func TestEncodeDecodePublicKeysEd25519(t *testing.T) { + pubkey, _, _ := ed25519.GenerateKey(rand.Reader) + + keystring, alg, err := EncodePublicKey(&pubkey) + if err != nil { + fmt.Println(err) + } + + fmt.Println(keystring, alg) + + decodedPkey, err := DecodePublicKey(keystring, alg) + if err != nil { + fmt.Println(err) + } + fmt.Println(reflect.TypeOf(decodedPkey)) + if !pubkey.Equal(decodedPkey) { + t.Errorf("string convert and parse failed (Ed25519)") + } + +} + +func TestEncodeDecodePublicKeysRSA(t *testing.T) { + originalKey, _ := rsa.GenerateKey(rand.Reader, 2048) + + pubkey := originalKey.PublicKey + + keystring, alg, err := EncodePublicKey(&pubkey) + if err != nil { + fmt.Println(err) + } + + fmt.Println(keystring, alg) + + decodedPkey, err := DecodePublicKey(keystring, alg) + if err != nil { + fmt.Println(err) + } + fmt.Println(reflect.TypeOf(decodedPkey)) + if !pubkey.Equal(decodedPkey) { + t.Errorf("string convert and parse failed (Ed25519)") + } + +} diff --git a/offlineauth/common/x509Ext.go b/offlineauth/common/x509Ext.go new file mode 100644 index 00000000..571314be --- /dev/null +++ b/offlineauth/common/x509Ext.go @@ -0,0 +1,82 @@ +package common + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "errors" +) + +var ( + RhineIndFlagExtOID = asn1.ObjectIdentifier{1, 3, 500, 9} +) + +type IndFlagExt struct { + Independent bool +} + +func CheckIndFlagX509Cert(cert x509.Certificate) (bool, error) { + exts := cert.Extensions + FlagExt, err := ParseIndFlagExt(exts) + if err != nil { + return false, err + } + + return FlagExt.Independent, nil +} + +func ParseIndFlagExt (exts []pkix.Extension) (IndFlagExt, error) { + if len(exts) == 0 { + return IndFlagExt{}, errors.New("No RhineIndFlagExt to parse") + } + + var rhineext *pkix.Extension + + for _, ext := range exts{ + if ext.Id.Equal(RhineIndFlagExtOID){ + rhineext = &ext + } + } + + if rhineext == nil { + return IndFlagExt{}, errors.New("ext OID is not RhineIndFlagExt") + } + var FlagExt IndFlagExt + _ , err := asn1.Unmarshal(rhineext.Value, &FlagExt) + if err != nil { + return IndFlagExt{}, err + } + return FlagExt, nil +} + +func CreateIndFlagExt (value bool) (pkix.Extension, error) { + data, err := asn1.Marshal(IndFlagExt{Independent: value}) + if err != nil { + return pkix.Extension{}, err + } + ext := pkix.Extension{ + Id: RhineIndFlagExtOID, + Critical: false, + Value: data, + } + + return ext, nil +} + +func FilterIndependentZoneCerts(certs []x509.Certificate) ([]x509.Certificate) { + var indCerts []x509.Certificate + for _ , cert := range certs { + isIndependent, err := CheckIndFlagX509Cert(cert) + if err != nil { + continue + } + if !isIndependent { + continue + } + indCerts = append(indCerts, cert) + + } + return indCerts +} + + diff --git a/offlineauth/common/x509Ext_test.go b/offlineauth/common/x509Ext_test.go new file mode 100644 index 00000000..d031e798 --- /dev/null +++ b/offlineauth/common/x509Ext_test.go @@ -0,0 +1,42 @@ +package common + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/x509" + "fmt" + "math/big" + "testing" + "time" +) + +func TestCertExtension(t *testing.T) { + + indtest := true + + pubkey, privkey, _ := ed25519.GenerateKey(rand.Reader) + var req x509.Certificate + req.DNSNames = append(req.DNSNames, "testcertext.rhine") + req.SerialNumber = big.NewInt(1) + req.NotBefore = time.Now() + req.NotAfter = time.Now().Add(time.Hour) + IndFlagExt, _ := CreateIndFlagExt(indtest) + //req.Extensions = append(req.Extensions, IndFlagExt) + req.ExtraExtensions = append(req.ExtraExtensions, IndFlagExt) + certbytes, err := x509.CreateCertificate(rand.Reader, &req, &req, pubkey, privkey) + if err != nil { + fmt.Println(err) + } + + certparsed, err := x509.ParseCertificate(certbytes) + + indreturn, err := CheckIndFlagX509Cert(*certparsed) + if err != nil { + fmt.Println(err) + t.Errorf("error checking ext") + } + if indreturn != indtest { + t.Errorf("check failed") + } + +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/ccreq.go b/offlineauth/cyrill-k/trustflex/common/ccreq.go new file mode 100644 index 00000000..6ed78440 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/ccreq.go @@ -0,0 +1,26 @@ +// This file holds definitions related to Certificate Confirmation + +package common + +type CCReq struct { + FirstCA string `json:"first_ca"` + SecondCA string `json:"second_ca"` + FirstILS string `json:"first_ils"` + EECert ByteEECert `json:"eecert"` + Signature Signature `json:"signature"` +} + +func (ccr *CCReq) ToVerify() CCReq { + return CCReq{FirstCA: ccr.FirstCA, SecondCA: ccr.SecondCA, FirstILS: ccr.FirstILS, EECert: ccr.EECert} +} + +type CCResp struct { + CCReq CCReq `json:"ccreq"` + PoP Proof `json:"pop"` + MultiSMR *MultiSignedMapRoot `json:"msmr"` +} + +type CCConf struct { + PoP Proof `json:"pop"` + MultiSMR *MultiSignedMapRoot `json:"msmr"` +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/constants.go b/offlineauth/cyrill-k/trustflex/common/constants.go new file mode 100644 index 00000000..39b60f1b --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/constants.go @@ -0,0 +1,38 @@ +package common + +const ( + HTTPS = "https://" + Local = "localhost" + BaseURL = HTTPS + Local + ILSPathPrefix = "/ils/" + CAPathPrefix = "/ca/" + + ILSCRReqPath = "cr-req" + ILSCCReqPath = "cc-req" + ILSCUReqPath = "cu-req" + ILSGetPoAPath = "get-poa" + ILSGetRootsPath = "get-roots" + ILSPoCPath = "get-poc" + ILSGetEntriesPath = "get-entries" + + CACRReqPath = "cr-req" + CRRespPath = "cr-resp" + CRConfPath = "cr-conf" + + CACCReqPath = "cc-req" + CCPopPath = "cc-pop" + CACCPopPath = "ca-cc-pop" + + CACUReqPath = "cu-req" + CACURespPath = "cu-resp" + CACUConfPath = "cu-conf" + + ContentTypeHeader = "Content-Type" + AppJsonHeader = "application/json" + + N = 3 + Ilses = 2 + Quorum = 1 +) + +var DefaultTreeNonce []byte = make([]byte, 32) diff --git a/offlineauth/cyrill-k/trustflex/common/crreq.go b/offlineauth/cyrill-k/trustflex/common/crreq.go new file mode 100644 index 00000000..4562d7ce --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/crreq.go @@ -0,0 +1,118 @@ +// This file holds definitions related to Certificate Registration + +package common + +import ( + "crypto" + "crypto/x509" + "encoding/json" + "fmt" + "github.com/google/certificate-transparency-go/tls" + "strconv" +) + +type CRReq struct { + EECert ByteEECert `json:"eecert"` + FirstCA string `json:"first_ca"` + SecondCA string `json:"second_ca"` + FirstILS string `json:"first_ils"` + Signature Signature `json:"signature"` +} + +func (crr *CRReq) ToVerify() CRReq { + return CRReq{EECert: crr.EECert, FirstCA: crr.FirstCA, SecondCA: crr.SecondCA, FirstILS: crr.FirstILS} +} + +type Accept struct { + EECertHash []byte `json:"eecert_hash"` + Timestamp int64 `json:"timestamp"` + Signatures map[string]Signature `json:"signatures"` +} + +func (a *Accept) ToVerify() Accept { + return Accept{EECertHash: a.EECertHash, Timestamp: a.Timestamp} +} + +func (a *Accept) VerifySignatures(publicKeys map[string]crypto.PublicKey) (bool, error) { + for id, sig := range a.Signatures { + jsonAccept, err := json.Marshal(a.ToVerify()) + if err != nil { + return false, fmt.Errorf("failed to marshal Accept %s: %s", id, err) + } + + err = tls.VerifySignature(publicKeys[id], jsonAccept, tls.DigitallySigned(sig)) + if err != nil { + return false, fmt.Errorf("failed to verify Accept signature %s: %s", id, err) + } + } + + return true, nil +} + +type CRResp struct { + Accept Accept `json:"accept"` + CRReq CRReq `json:"crreq"` + SynAcks []SynAck `json:"syn_acks"` + Signature Signature `json:"signature"` +} + +func (crrsp *CRResp) ToVerify() CRResp { + return CRResp{Accept: crrsp.Accept, CRReq: crrsp.CRReq, SynAcks: crrsp.SynAcks} +} + +type CRConf struct { + FirstCA string `json:"first_ca"` + SecondCA string `json:"second_ca"` + FirstILS string `json:"first_ils"` + Accept Accept `json:"accept"` + SynAcks []SynAck `json:"syn_acks"` + Signature Signature `json:"signature"` +} + +func (crc *CRConf) ToVerify() CRConf { + return CRConf{FirstCA: crc.FirstCA, SecondCA: crc.SecondCA, FirstILS: crc.FirstILS, Accept: crc.Accept, SynAcks: crc.SynAcks} +} + +type SynReq struct { + CoordId string `json:"coord_id"` + Request CRReq `json:"cr_req"` + Type int `json:"type"` + Signature Signature `json:"hash_sig"` +} + +func (s *SynReq) VerifySignature(certificate *x509.Certificate) error { + pubKey := certificate.PublicKey + fields := AppendToByteSlice(s.Request, s.CoordId, strconv.Itoa(s.Type), "Node failed to marshal CRReq in SYN-REQ: %s") + return tls.VerifySignature(pubKey, fields, tls.DigitallySigned(s.Signature)) +} + +type SynResp struct { + Hash []byte `json:"hashed_req"` + Signature Signature `json:"syn_resp_signature"` +} + +func (s *SynResp) VerifySignature(certificate *x509.Certificate) error { + pubKey := certificate.PublicKey + return tls.VerifySignature(pubKey, s.Hash, tls.DigitallySigned(s.Signature)) +} + +type SynCommit struct { + Hash []byte `json:"hashed_req"` + Signature Signature `json:"syn_commit_signature"` +} + +func (s *SynCommit) VerifySignature(certificate *x509.Certificate) error { + pubKey := certificate.PublicKey + return tls.VerifySignature(pubKey, s.Hash, tls.DigitallySigned(s.Signature)) +} + +type SynAck struct { + ID string `json:"id"` + Hash []byte `json:"hashed_req"` + Signature Signature `json:"syn_ack_signature"` +} + +func (s *SynAck) VerifySignature(certificate *x509.Certificate) error { + pubKey := certificate.PublicKey + return tls.VerifySignature(pubKey, s.Hash, tls.DigitallySigned(s.Signature)) +} diff --git a/offlineauth/cyrill-k/trustflex/common/csv.go b/offlineauth/cyrill-k/trustflex/common/csv.go new file mode 100644 index 00000000..ee2e43a5 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/csv.go @@ -0,0 +1,82 @@ +// This file holds various functions +// used by different entities + +package common + +import ( + "encoding/csv" + "fmt" + "io" +) + +type DroppedLogEntry struct { + CtLogIndex int64 + Error error +} + +type DroppedLogEntryWriter struct { + Writer *csv.Writer +} + +func NewDroppedLogEntryWriter(w io.Writer) *DroppedLogEntryWriter { + return &DroppedLogEntryWriter{Writer: csv.NewWriter(w)} +} + +func (w *DroppedLogEntryWriter) Close() { + w.Writer.Flush() +} + +func (w *DroppedLogEntryWriter) Write(p *DroppedLogEntry) error { + return w.Writer.Write([]string{fmt.Sprintf("%d", p.CtLogIndex), p.Error.Error()}) +} + +type ProofPerformanceInfo struct { + CurrentIdx int64 + Domain string + + // all certificates including intermediate certificates + NCertificates int64 + // use to see possible how many overlapping intermediate certificates there are + NUniqueCertificates int64 + // calculate possible savings from encoding certificates in a smart way + UniqueCertificatesSize int64 + + // see how many domains already adhere to the uniqueness policy + NLeafCertificates int64 + NUniquePublicKeys int64 + + // check how many domains have the same public key for the exact domain (e.g., test.example.com without example.com certificates) + NLeafCertificatesForExactDomain int64 + NUniquePublicKeysForExactDomain int64 + // check how many wildcard certificates have the same public key (e.g., test.example.com and *.example.com without example.com) + NLeafCertificatesForExactDomainOrWildcard int64 + NUniquePublicKeysForExactDomainOrWildcard int64 + + // time it takes mapClient.GetProofForDomains() to finish in nanonsecods + GetProofTime int64 + // size of the complete DER encoded proof + ProofSize int64 + // size of the encoded inclusion proofs + InclusionProofSize int64 + // size of the compressed DER encoded proof + CompressedProofSize int64 + + // check how many CAs issued certificates + NUniqueRootCACertificates int64 +} + +type ProofPerformanceInfoWriter struct { + Writer *csv.Writer +} + +func NewProofPerformanceInfoWriter(w io.Writer) *ProofPerformanceInfoWriter { + return &ProofPerformanceInfoWriter{Writer: csv.NewWriter(w)} +} + +func (w *ProofPerformanceInfoWriter) Close() { + w.Writer.Flush() +} + +func (w *ProofPerformanceInfoWriter) StoreProofPerformanceInfoEntry(p *ProofPerformanceInfo) error { + return w.Writer.Write([]string{fmt.Sprintf("%d", p.CurrentIdx), p.Domain, fmt.Sprintf("%d", p.NCertificates), fmt.Sprintf("%d", p.NUniqueCertificates), fmt.Sprintf("%d", p.UniqueCertificatesSize), fmt.Sprintf("%d", p.NLeafCertificates), fmt.Sprintf("%d", p.NUniquePublicKeys), fmt.Sprintf("%d", p.NLeafCertificatesForExactDomain), fmt.Sprintf("%d", p.NUniquePublicKeysForExactDomain), fmt.Sprintf("%d", p.NLeafCertificatesForExactDomainOrWildcard), fmt.Sprintf("%d", p.NUniquePublicKeysForExactDomainOrWildcard), fmt.Sprintf("%d", p.GetProofTime), fmt.Sprintf("%d", p.ProofSize), fmt.Sprintf("%d", p.InclusionProofSize), fmt.Sprintf("%d", p.CompressedProofSize), fmt.Sprintf("%d", p.NUniqueRootCACertificates)}) +} diff --git a/offlineauth/cyrill-k/trustflex/common/cupdate.go b/offlineauth/cyrill-k/trustflex/common/cupdate.go new file mode 100644 index 00000000..79cef7ac --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/cupdate.go @@ -0,0 +1,74 @@ +// This file holds definitions related to Certificate Update + +package common + +import ( + "crypto" + "encoding/json" + "fmt" + "github.com/google/certificate-transparency-go/tls" +) + +type CUReq struct { + EECert ByteEECert `json:"eecert"` + OldEECert ByteEECert `json:"old_eecert"` + FirstCA string `json:"first_ca"` + SecondCA string `json:"second_ca"` + FirstILS string `json:"first_ils"` + Signature Signature `json:"signature"` +} + +func (cur *CUReq) ToVerify() CUReq { + return CUReq{EECert: cur.EECert, OldEECert: cur.OldEECert, FirstCA: cur.FirstCA, SecondCA: cur.SecondCA, FirstILS: cur.FirstILS} +} + +type UAccept struct { + EECertHash []byte `json:"eecert_hash"` + Timestamp int64 `json:"timestamp"` + Signatures map[string]Signature `json:"signatures"` +} + +func (ua *UAccept) ToVerify() UAccept { + return UAccept{EECertHash: ua.EECertHash, Timestamp: ua.Timestamp} +} + + +func (ua *UAccept) VerifySignatures(publicKeys map[string]crypto.PublicKey) (bool, error) { + for id, sig := range ua.Signatures { + jsonUAccept, err := json.Marshal(ua.ToVerify()) + if err != nil { + return false, fmt.Errorf("failed to marshal UAccept %s: %s", id, err) + } + + err = tls.VerifySignature(publicKeys[id], jsonUAccept, tls.DigitallySigned(sig)) + if err != nil { + return false, fmt.Errorf("failed to verify UAccept signature %s: %s", id, err) + } + } + + return true, nil +} + +type CUResp struct { + UAccept UAccept `json:"uaccept"` + CUReq CUReq `json:"cureq"` + SynAcks []SynAck `json:"synacks"` + Signature Signature `json:"signature"` +} + +func (cursp *CUResp) ToVerify() CUResp { + return CUResp{UAccept: cursp.UAccept, CUReq: cursp.CUReq, SynAcks: cursp.SynAcks} +} + +type CUConf struct { + FirstCA string `json:"first_ca"` + SecondCA string `json:"second_ca"` + FirstILS string `json:"first_ils"` + UAccept UAccept `json:"uaccept"` + SynAcks []SynAck `json:"synacks"` + Signature Signature `json:"signature"` +} + +func (cuc *CUConf) ToVerify() CUConf { + return CUConf{FirstCA: cuc.FirstCA, SecondCA: cuc.SecondCA, FirstILS: cuc.FirstILS, UAccept: cuc.UAccept, SynAcks: cuc.SynAcks} +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/dns.go b/offlineauth/cyrill-k/trustflex/common/dns.go new file mode 100644 index 00000000..bee11858 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/dns.go @@ -0,0 +1,118 @@ +// domain related functions + +package common + +import ( + "fmt" + "github.com/miekg/dns" + "log" + "time" +) + +func BytesToStrings(in []byte) []string { + var out []string + for i := range in { + if i%255 == 0 { + out = append(out, "") + } + //out[len(out)-1] += string(in[i]) + out[len(out)-1] += fmt.Sprintf("\\%d%d%d", in[i]/100%10, in[i]/10%10, in[i]%10) + } + + return out +} + +func StringsToBytes(in []string) []byte { + var out []byte + for _, s := range in { + for i := 0; i < len(s); i++ { + if s[i] == '\\' { + i++ + if i == len(s) { + break + } + // check for \DDD + if i+2 < len(s) && isDigit(s[i]) && isDigit(s[i+1]) && isDigit(s[i+2]) { + out = append(out, dddStringToByte(s[i:])) + i += 2 + } else { + out = append(out, byte(s[i])) + } + } else { + out = append(out, byte(s[i])) + } + } + } + return out +} + +func isDigit(b byte) bool { return b >= '0' && b <= '9' } + +func dddToByte(s []byte) byte { + _ = s[2] // bounds check hint to compiler; see golang.org/issue/14808 + return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0')) +} + +func dddStringToByte(s string) byte { + _ = s[2] // bounds check hint to compiler; see golang.org/issue/14808 + return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0')) +} + +// SetupEdns0Opt will retrieve the EDNS0 OPT or create it if it does not exist. +func SetupEdns0Opt(r *dns.Msg, length uint16) *dns.OPT { + o := r.IsEdns0() + if o == nil { + r.SetEdns0(length, false) + o = r.IsEdns0() + } + return o +} + +func RetrieveTxtRecord(domain string, resolverAddress string, tcpOnly bool) ([]byte, error) { + // query DNS proof entry + var resp *dns.Msg + var rtt time.Duration + var err error + + if !tcpOnly { + m := new(dns.Msg) + m.SetQuestion(domain, dns.TypeTXT) + SetupEdns0Opt(m, 4096) + c := new(dns.Client) + resp, rtt, err = c.Exchange(m, resolverAddress) + if err != nil { + return nil, fmt.Errorf("Failed to query map server: %s", err) + } + } + if tcpOnly || resp.Truncated { + if !tcpOnly { + log.Print("DNS (UDP) response truncated; Retrying with TCP ...") + } + cTcp := dns.Client{Net: "tcp"} + mTcp := new(dns.Msg) + mTcp.SetQuestion(domain, dns.TypeTXT) + SetupEdns0Opt(mTcp, 65507) + resp, rtt, err = cTcp.Exchange(mTcp, resolverAddress) + if err != nil { + return nil, fmt.Errorf("Failed to query map server using TCP: %s", err) + } + if resp.Truncated { + return nil, fmt.Errorf("DNS server returned a truncated DNS TCP reply") + } + } + + // extract bytes from txt records + t0 := time.Now() + var txtBytes []byte + if txt, ok := resp.Answer[0].(*dns.TXT); !ok { + return nil, fmt.Errorf("DNS reply does not contain TXT record") + } else { + txtBytes = StringsToBytes(txt.Txt) + } + t1 := time.Now() + _ = rtt + _ = t0 + _ = t1 + //log.Printf("rtt = %s, extraction = %s", rtt, t1.Sub(t0)) + return txtBytes, nil +} diff --git a/offlineauth/cyrill-k/trustflex/common/domain.go b/offlineauth/cyrill-k/trustflex/common/domain.go new file mode 100644 index 00000000..c0ccaa2d --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/domain.go @@ -0,0 +1,154 @@ +// domain related functions + +package common + +import ( + "log" + "regexp" + "strings" +) + +const ( + MaxDomainLength = 255 +) + +var ( + viableDomain *regexp.Regexp + wildcardDomain *regexp.Regexp + incorrectLabel *regexp.Regexp + correctLabel *regexp.Regexp +) + +func init() { + var err error + wildcardDomain, err = regexp.Compile("^\\*\\..*$") + LogError("Couldn't compile wildcard domain regexp: %s", err) + // todo(cyrill) also perform other checks except the wildcard check (e.g., only allowed characters) + viableDomain, err = regexp.Compile("^(\\*\\.)?[^*]*$") + LogError("Couldn't compile viable domain regexp: %s", err) + + incorrectLabel, err = regexp.Compile("^[[:digit:]]*$") + // correctLabel, err = regexp.Compile("^(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,63}(? 1 && len(parentDomainShort) > 1 && strings.HasSuffix("."+strings.Join(domainShort[1:], "."), "."+strings.Join(parentDomainShort[1:], ".")) { + return true + } + // domainShort := strings.Join(SplitE2LD(domain), ".") + // parentShort := strings.Join(SplitE2LD(parentDomain), ".") + // if len(domainShort) > 1 && len(parentShort) > 1 && strings.HasSuffix(domainShort[1:], "."+parentShort[1:]) { + // return true + // } + } + return false +} + +func IsSameDomain(domain1, domain2 string) bool { + if domain1 == domain2 { + return true + } + if IsWildcardDomain(domain1) || IsWildcardDomain(domain2) { + domain1Short, err := SplitE2LD(domain1) + if err != nil { + log.Printf("Cannot split %s into E2LD and subdomains: %s", domain1, err) + return false + } + domain2Short, err := SplitE2LD(domain2) + if err != nil { + log.Printf("Cannot split %s into E2LD and subdomains: %s", domain2, err) + return false + } + if len(domain1Short) > 1 && len(domain2Short) > 1 && strings.Join(domain1Short[1:], ".") == strings.Join(domain2Short[1:], ".") { + return true + } + } + return false +} + +// only allow wildcards for the deepest subdomain +func IsViableDomain(domain string) bool { + // removes domains with wildcard labels other than the first label + if !viableDomain.Match([]byte(domain)) { + return false + } + // remove long domains + if len(domain) > MaxDomainLength { + return false + } + for _, n := range strings.Split(domain, ".") { + // remove numeric labels + if incorrectLabel.Match([]byte(n)) { + return false + } + // remove invalid characters and hyphens at the beginning and end + if !correctLabel.Match([]byte(n)) { + return false + } + } + return true +} + +// is the deepest subdomain a wildcard domain +func IsWildcardDomain(domain string) bool { + return wildcardDomain.Match([]byte(domain)) +} + +func IsE2LD(domain string) bool { + labels, err := SplitE2LD(domain) + return err == nil && len(labels) == 1 +} + +func SplitE2LD(domain string) ([]string, error) { + //if !IsViableDomain(domain) { + // return nil, fmt.Errorf("'%s' is not a viable domain", domain) + //} + //u, err := url.Parse("http://" + domain) + //if err != nil { + // return nil, fmt.Errorf("Couldn't parse url '%s': %s", domain, err) + //} + //if u.Hostname() != domain { + // return nil, fmt.Errorf("input contains non-domain related characters: '%s' != '%s'", domain, u.Hostname()) + //} + //_, hasPublicSuffix := publicsuffix.PublicSuffix(domain) + //if !hasPublicSuffix { + // return nil, fmt.Errorf("'%s' does not have a public suffix", domain) + //} + //e2LD, err := publicsuffix.EffectiveTLDPlusOne(domain) + //if err != nil { + // return []string{domain}, nil + // return nil, fmt.Errorf("couldn't extract e2LD of '%s': %s", domain, err) + //} + //domain = strings.TrimSuffix(domain, e2LD) + //domain = strings.TrimSuffix(domain, ".") + //var subdomains []string + //if domain != "" { + // subdomains = strings.Split(domain, ".") + //} + //subdomains = append(subdomains, e2LD) + //return subdomains, nil + return []string{domain}, nil +} + +func IsWildcardLabel(label string) bool { + return label == "*" +} diff --git a/offlineauth/cyrill-k/trustflex/common/domain_test.go b/offlineauth/cyrill-k/trustflex/common/domain_test.go new file mode 100644 index 00000000..75d806a3 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/domain_test.go @@ -0,0 +1,65 @@ +package common + +import ( + "fmt" + "testing" +) + +func TestIsViableDomain(t *testing.T) { + tests := map[string]bool{ + "01010": false, + "abc": true, + "A0c": true, + "A0c-": false, + "-A0c": false, + "A-0c": true, + "o123456701234567012345670123456701234567012345670123456701234567": false, + "o12345670123456701234567012345670123456701234567012345670123456": true, + "": false, + "a": true, + "0--0": true, + } + for label, result := range tests { + if IsViableDomain(label) != result { + t.Errorf("IsViableDomain(%s) != %+v", label, result) + } + } +} + +func TestSplitE2LD(t *testing.T) { + tests := map[string][]string{ + "a.b.com": []string{"a", "b.com"}, + "a.b.invalid": []string{}, + "a.b.c.d.com": []string{"a", "b", "c", "d.com"}, + "a.ac.jp": []string{"a.ac.jp"}, + "-.com": []string{}, + } + for domain, labels := range tests { + x, err := SplitE2LD(domain) + fmt.Println(err) + if !StringSliceCompare(x, labels) { + t.Errorf("SplitE2LD(%s) = %+v != %+v", domain, x, labels) + } + } +} + + +func TestSplitE2LD2(t *testing.T) { + tests := map[string][]string{ + "a.b.com": []string{"a", "b.com"}, + "a.b.invalid": []string{}, + "a.b.c.d.com": []string{"a", "b", "c", "d.com"}, + "a.ac.jp": []string{"a.ac.jp"}, + "-.com": []string{}, + "ethz.ch": nil, + "ch":nil, + "inf.ethz.ch": nil, + + } + for domain, _ := range tests { + x, err := SplitE2LD(domain) + fmt.Println(x) + fmt.Println(err) + + } +} diff --git a/offlineauth/cyrill-k/trustflex/common/eecert.go b/offlineauth/cyrill-k/trustflex/common/eecert.go new file mode 100644 index 00000000..e391f8d2 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/eecert.go @@ -0,0 +1,68 @@ +package common + +import ( + "crypto/sha256" + "crypto/x509" + "encoding/json" + "github.com/golang/protobuf/ptypes/timestamp" + ct "github.com/google/certificate-transparency-go" +) + +// An EECert is a sequence of PEM encoded x509 Certificates +type EECert []*x509.Certificate +type ByteEECert []byte + +// BFTEECert is specifically used during the BFT protocol, +// since it allows to distinguish between a new addition +// and an update +type BFTEECert struct { + IsNew bool + EECert ByteEECert +} + +// LogEntry is returned by the GetEntries interface +type LogEntry struct { + LeafValue []byte `json:"value"` + Timestamp *timestamp.Timestamp `json:"timestamp"` +} + +// Returns the key under which the EECert is/will be stored +// in the Trillian Map +func MapKeyFromByteEECert(byteEECert ByteEECert) ([]byte, error) { + eecert, err := x509.ParseCertificates(byteEECert) + if err != nil { + return nil, err + } + + return MapKeyFromEECert(eecert), nil +} + +func MapKeyFromEECert(eeCert []*x509.Certificate) []byte { + domain := eeCert[0].Subject.CommonName + return MapKeyFromDomain(domain) +} + +func MapKeyFromDomain(domain string) []byte { + key := sha256.Sum256([]byte(domain)) + return key[:] +} + +func LeafHashFromByteEECert(byteEECert []byte) ([]byte, error) { + jsonCert, err := json.Marshal(byteEECert) + if err != nil { + return nil, err + } + + hashedEECert := sha256.Sum256(append([]byte{ct.TreeLeafPrefix}, jsonCert...)) + return hashedEECert[:], nil +} + +// Returns the domain given an encoded EECert +func DomainFromByteEECert(byteEECert ByteEECert) (string, error) { + eecert, err := x509.ParseCertificates(byteEECert) + if err != nil { + return "", err + } + + return eecert[0].Subject.CommonName, nil +} diff --git a/offlineauth/cyrill-k/trustflex/common/httputil.go b/offlineauth/cyrill-k/trustflex/common/httputil.go new file mode 100644 index 00000000..0546ac91 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/httputil.go @@ -0,0 +1,109 @@ +// This file holds some common code related to HTTP +// used by different entities + +package common + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" +) + +func setUpClient(cert []byte) *http.Client { + CAPool := x509.NewCertPool() + CAPool.AppendCertsFromPEM(cert) + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: CAPool}}} + return client +} + +func SetUpClientFromFile(certFile string) (*http.Client, error) { + cert, err := ioutil.ReadFile(certFile) + if err != nil { + return nil, err + } + + return setUpClient(cert), nil +} + +func ReadHTTPBody(reqStruct interface{}, r io.Reader) ([]byte, error){ + body, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + err = json.Unmarshal(body, reqStruct) + if err != nil { + return nil, err + } + return body, nil +} + +func LogResponse(msg string, resp *http.Response) { + log.Println(msg) + log.Println("Response Status:", resp.Status) + log.Println("Response Headers:", resp.Header) + body, err := ioutil.ReadAll(resp.Body) + LogError("failed to read response body: %s", err) + if len(body) > 0 { + log.Println("Response Body:", string(body)) + } +} + +func SendHTTPError(status int, err error, w http.ResponseWriter) { + errMsg := fmt.Errorf(http.StatusText(status) + ": %s", err) + http.Error(w, errMsg.Error(), status) +} + +func SendResponseBack(resp interface{}, w http.ResponseWriter) error { + jsonMsg, err := json.Marshal(resp) + if err != nil { + return err + } + + _, err = w.Write(jsonMsg) + if err != nil { + return err + } + + return nil +} + +func PostAndParseResp(req interface{}, url string, client *http.Client) (*http.Response, int, error) { + jsonReq, err := json.Marshal(req) + if err != nil { + return nil, http.StatusInternalServerError, fmt.Errorf("failed to marshal request: %s", err) + } + + httpReq, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonReq)) + if err != nil { + return nil, http.StatusInternalServerError, fmt.Errorf("failed to create new HTTP request: %s", err) + } + + httpReq.Header.Set(ContentTypeHeader, AppJsonHeader) + + resp, err := client.Do(httpReq) + if err != nil { + return nil, http.StatusServiceUnavailable, fmt.Errorf("failed to contact client: %s", err) + } + + return resp, resp.StatusCode, nil +} + +func CheckRespStatus(resp *http.Response) error { + if resp.StatusCode != http.StatusOK { + body, _ := ioutil.ReadAll(resp.Body) + resp.Body.Close() + return errors.New(string(body)) + } + + return nil +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/id.go b/offlineauth/cyrill-k/trustflex/common/id.go new file mode 100644 index 00000000..c4f4e3a2 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/id.go @@ -0,0 +1,62 @@ +package common + +import ( + "crypto" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/json" + "fmt" +) + +// This is based on CT logid package +// ID is the hash of the entitiy's public key +type ID [sha256.Size]byte + +func IDFromAuthorityKeyId(x *x509.Certificate) ID { + return ID(sha256.Sum256(x.AuthorityKeyId)) +} + +// Returns the ID of an entity from the given certificate file +func IDFromCertFile(file string) (ID, error) { + cert, err := CertFromFile(file) + if err != nil { + return ID{}, err + } + pubKey := PubKeyFromCert(cert) + return IDFromPublicKey(pubKey) +} + +// Returns the ID of an entity from the given public key +func IDFromPublicKey(pubKey crypto.PublicKey) (ID, error) { + bytePubKey, err := json.Marshal(pubKey) + + if err != nil { + return ID{}, fmt.Errorf("failed to marshal public key: %s", err) + } + + return ID(sha256.Sum256(bytePubKey)), nil +} + +// Returns the ID of an entity from the given public key +func SubjectPublicKeyInfoDigest(cert *x509.Certificate) (ID, error) { + return ID(sha256.Sum256(cert.RawSubjectPublicKeyInfo)), nil +} + +// Returns the ID created from a DER byte slice +func CertIDFromDER(certDER []byte) ID { + return ID(sha256.Sum256(certDER)) +} + +// Returns the ID created from a DER byte slice +func X509ID(x *x509.Certificate) ID { + return CertIDFromDER(x.Raw) +} + +func (id ID) Bytes() []byte { + return id[:] +} + +func (id ID) String() string { + return fmt.Sprintf("%s", base64.StdEncoding.EncodeToString(id.Bytes())) +} diff --git a/offlineauth/cyrill-k/trustflex/common/misc.go b/offlineauth/cyrill-k/trustflex/common/misc.go new file mode 100644 index 00000000..fcbba95a --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/misc.go @@ -0,0 +1,208 @@ +// This file holds various functions +// used by different entities + +package common + +import ( + "encoding/gob" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "os/signal" + "sort" + "syscall" +) + +var ( + DisableLogging bool + EnableDebug bool +) + +func OpenOrCreate(filename string) (*os.File, error) { + info, _ := os.Stat(filename) + if info != nil && info.IsDir() { + return nil, fmt.Errorf("Cannot create or open: '%s' is a directory", filename) + } + return os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) +} + +func Min(a, b int64) int64 { + if a < b { + return a + } + return b +} + +func LoadConfig(fileName string, config interface{}) { + jsonFile, err := os.Open(fileName) + LogError("Failed to open "+fileName+": %s", err) + + byteFile, err := ioutil.ReadAll(jsonFile) + LogError("Failed to read "+fileName+": %s", err) + + LogError("Failed to close "+fileName+": %s", jsonFile.Close()) + + err = json.Unmarshal(byteFile, &config) + LogError("Failed to unmarshal json into struct: %s", err) + +} + +func SliceIncludes(slice []string, element string) bool { + for _, s := range slice { + if s == element { + return true + } + } + return false +} + +func MapKeysSlice(ogMap map[string][]byte) []string { + keys := make([]string, len(ogMap)) + idx := 0 + for key, _ := range ogMap { + keys[idx] = key + idx++ + } + + sort.Slice(keys, func(i, j int) bool { + return keys[i] < keys[j] + }) + + return keys +} + +func AppendToByteSlice(data interface{}, id string, typ string, errMsg string) []byte { + byteData, err := json.Marshal(data) + LogError(errMsg, err) + byteId := []byte(id) + byteType := []byte(typ) + var fields []byte + fields = append(fields, byteData...) + fields = append(fields, byteId...) + fields = append(fields, byteType...) + return fields +} + +func AwaitSignal(function func()) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + sig := <-sigs + log.Printf("Signal received: %v", sig) + function() +} + +func LogError(msg string, err error) { + if err != nil { + log.Printf(msg, err) + } +} + +func Log(s string, args ...interface{}) { + if !DisableLogging { + log.Printf(s, args...) + } +} + +func Debug(s string, args ...interface{}) { + if EnableDebug { + log.Printf(s, args...) + } +} + +func StringSliceCompare(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, ae := range a { + if ae != b[i] { + return false + } + } + return true +} + +func GetAverages(m map[int64][]int64) (avg map[int64]float64) { + avg = make(map[int64]float64) + for k := range m { + avg[k] = 0 + for _, x := range m[k] { + avg[k] += float64(x) + } + avg[k] /= float64(len(m[k])) + } + return avg +} + +func GobWriteMapIntSlice(f string, m map[int64][]int64) error { + dataFile, err := os.Create(f) + if err != nil { + return err + } + defer dataFile.Close() + + dataDecoder := gob.NewEncoder(dataFile) + err = dataDecoder.Encode(m) + if err != nil { + return err + } + + return nil +} + +func GobReadMapIntSlice(f string, m *map[int64][]int64) error { + if _, err := os.Stat(f); os.IsNotExist(err) { + *m = make(map[int64][]int64) + return nil + } + dataFile, err := os.Open(f) + if err != nil { + return err + } + defer dataFile.Close() + + dataDecoder := gob.NewDecoder(dataFile) + err = dataDecoder.Decode(m) + if err != nil { + return err + } + + return nil +} + +func GobWriteMapBool(f string, m map[string]bool) error { + dataFile, err := os.Create(f) + if err != nil { + return err + } + defer dataFile.Close() + + dataDecoder := gob.NewEncoder(dataFile) + err = dataDecoder.Encode(m) + if err != nil { + return err + } + + return nil +} + +func GobReadMapBool(f string, m *map[string]bool) error { + if _, err := os.Stat(f); os.IsNotExist(err) { + *m = make(map[string]bool) + return nil + } + dataFile, err := os.Open(f) + if err != nil { + return err + } + defer dataFile.Close() + + dataDecoder := gob.NewDecoder(dataFile) + err = dataDecoder.Decode(m) + if err != nil { + return err + } + + return nil +} diff --git a/offlineauth/cyrill-k/trustflex/common/mslr.go b/offlineauth/cyrill-k/trustflex/common/mslr.go new file mode 100644 index 00000000..35807a8a --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/mslr.go @@ -0,0 +1,129 @@ +// Definitions related to a Multi-Signed Log Root + +package common + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "encoding/json" + "fmt" + "github.com/google/certificate-transparency-go/tls" + "github.com/google/trillian/types" + "io/ioutil" + "log" + "strings" +) + +type MultiSignedLogRoot struct { + Root *types.LogRootV1 + Signatures map[string]Signature +} + +func NewMSLR(root *types.LogRootV1) *MultiSignedLogRoot { + mslr := &MultiSignedLogRoot{Root: root} + mslr.Signatures = make(map[string]Signature) + return mslr +} + +func (mslr *MultiSignedLogRoot) Sign(id string, privKey crypto.PrivateKey, hashAlgorithm tls.HashAlgorithm) error { + + var err error + var ds tls.DigitallySigned + + switch privKey := privKey.(type) { + + case ecdsa.PrivateKey: + var sig Sig + sig.R, sig.S, err = ecdsa.Sign(rand.Reader, &privKey, mslr.Root.RootHash) + if err != nil { + return fmt.Errorf("failed to sign MSLR: %s", err) + } + + signature, err := sig.Convert(tls.ECDSA, hashAlgorithm) + if err != nil { + return fmt.Errorf("could not convert ECDSA signature: %s", err) + } + log.Printf("Signature algorithm: %v", signature.Algorithm) + mslr.Signatures[id] = signature + return nil + + case rsa.PrivateKey: + ds.Signature, err = rsa.SignPKCS1v15(rand.Reader, &privKey, crypto.SHA256, mslr.Root.RootHash) + ds.Algorithm.Hash = hashAlgorithm + ds.Algorithm.Signature = tls.RSA + mslr.Signatures[id] = Signature(ds) + return nil + + default: + return fmt.Errorf("%T private key is not supported", privKey) + } + +} + +func (mslr *MultiSignedLogRoot) Verify(validID string, pubKeys map[string]crypto.PublicKey) (bool, error) { + rootHash := mslr.Root.RootHash + signature := mslr.Signatures[validID] // assume all signatures are using the same algorithm + algorithm := signature.Algorithm.Signature + var err error + var sig Sig + + switch algorithm { + + case tls.RSA: + for idx, sig := range mslr.Signatures { + pubKey, ok := pubKeys[idx].(*rsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot verify %s signature with %T", idx, pubKey) + } + + if err := rsa.VerifyPKCS1v15(pubKey, TLSToCryptoHash(signature.Algorithm.Hash), rootHash, sig.Signature); err != nil { + return false, fmt.Errorf("signature verification %s failed: %s", idx, err) + } + } + + return true, nil + + case tls.ECDSA: + for idx, sign := range mslr.Signatures { + pubKey, ok := pubKeys[idx].(*ecdsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot verify %s signature with %T", idx, pubKey) + } + + sig, err = ConvertBack(sign) + if err != nil { + return false, fmt.Errorf("failed to convert signature %s: %s", idx, err) + } + + if !ecdsa.Verify(pubKey, rootHash, sig.R, sig.S) { + return false, fmt.Errorf("signature verification %s failed", idx) + } + } + + return true, nil + + default: + return false, fmt.Errorf("%s is not a supported algorithm type", algorithm) + + } + +} + +func (mslr *MultiSignedLogRoot) Publish(id string) error { + jsonMSLR, err := json.Marshal(mslr) + if err != nil { + return err + } + + id = strings.ReplaceAll(id, "/", "") + err = ioutil.WriteFile("trillian/mslr-"+strings.ReplaceAll(id, "/", ""), jsonMSLR, 0644) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/msmr.go b/offlineauth/cyrill-k/trustflex/common/msmr.go new file mode 100644 index 00000000..08af3980 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/msmr.go @@ -0,0 +1,131 @@ +// Definitions related to a Multi-Signed Map Root + +package common + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "encoding/json" + "fmt" + "github.com/google/certificate-transparency-go/tls" + "github.com/google/trillian/types" + "io/ioutil" + "log" + "strings" +) + +type MultiSignedMapRoot struct { + Root *types.MapRootV1 + Signatures map[string]Signature +} + +func NewMSMR(root *types.MapRootV1) *MultiSignedMapRoot { + msmr := &MultiSignedMapRoot{Root: root} + msmr.Signatures = make(map[string]Signature) + return msmr +} + +func (msmr *MultiSignedMapRoot) Sign(id string, privKey crypto.PrivateKey, hashAlgorithm tls.HashAlgorithm) error { + + var err error + var ds tls.DigitallySigned + + switch privKey := privKey.(type) { + + case ecdsa.PrivateKey: + var sig Sig + sig.R, sig.S, err = ecdsa.Sign(rand.Reader, &privKey, msmr.Root.RootHash) + if err != nil { + return fmt.Errorf("failed to sign MSMR: %s", err) + } + + signature, err := sig.Convert(tls.ECDSA, hashAlgorithm) + if err != nil { + return fmt.Errorf("could not convert ECDSA signature: %s", err) + } + log.Printf("Signature algorithm: %v", signature.Algorithm) + msmr.Signatures[id] = signature + return nil + + case rsa.PrivateKey: + ds.Signature, err = rsa.SignPKCS1v15(rand.Reader, &privKey, crypto.SHA256, msmr.Root.RootHash) + ds.Algorithm.Hash = hashAlgorithm + ds.Algorithm.Signature = tls.RSA + msmr.Signatures[id] = Signature(ds) + return nil + + default: + return fmt.Errorf("%T private key is not supported", privKey) + } + +} + +func (msmr *MultiSignedMapRoot) Verify(validID string, pubKeys map[string]crypto.PublicKey) (bool, error) { + rootHash := msmr.Root.RootHash + signature := msmr.Signatures[validID] + algorithm := signature.Algorithm.Signature + var err error + var sig Sig + + switch algorithm { + + case tls.RSA: + for idx, sig := range msmr.Signatures { + pubKey, ok := pubKeys[idx].(*rsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot verify %s signature with %T", idx, pubKey) + } + + if err := rsa.VerifyPKCS1v15(pubKey, TLSToCryptoHash(signature.Algorithm.Hash), rootHash, sig.Signature); err != nil { + return false, fmt.Errorf("signature verification %s failed: %s", idx, err) + } + } + + return true, nil + + case tls.ECDSA: + for idx, sign := range msmr.Signatures { + pubKey, ok := pubKeys[idx].(*ecdsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot verify %s signature with %T", idx, pubKey) + } + + sig, err = ConvertBack(sign) + if err != nil { + return false, fmt.Errorf("failed to convert signature %s: %s", idx, err) + } + + if !ecdsa.Verify(pubKey, rootHash, sig.R, sig.S) { + return false, fmt.Errorf("signature verification %s failed", idx) + } + } + + return true, nil + + default: + return false, fmt.Errorf("%d is not a supported algorithm type", algorithm) + + } + +} + +// Publish is used at the end of the Signing phase, +// and writes the MSMR to a file +func (msmr *MultiSignedMapRoot) Publish(id string) error { + jsonMSMR, err := json.Marshal(msmr) + if err != nil { + return err + } + + id = strings.ReplaceAll(id, "/", "") + err = ioutil.WriteFile("trillian/msmr-"+strings.ReplaceAll(id, "/", ""), jsonMSMR, 0644) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/node.go b/offlineauth/cyrill-k/trustflex/common/node.go new file mode 100644 index 00000000..b3f49cbb --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/node.go @@ -0,0 +1,17 @@ +package common + +import ( + "crypto/sha256" + "crypto/x509" +) + +// An EECert is a sequence of PEM encoded x509 Certificates +type Cert *x509.Certificate +type ByteCert []byte + +func GenerateMapKey(treeNonce []byte, domain string) []byte { + h := sha256.New() + h.Write(treeNonce) + h.Write([]byte(domain)) + return h.Sum(nil) +} diff --git a/offlineauth/cyrill-k/trustflex/common/proofs.go b/offlineauth/cyrill-k/trustflex/common/proofs.go new file mode 100644 index 00000000..24a7f4db --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/proofs.go @@ -0,0 +1,116 @@ +// Trillian proofs' definitions + +package common + +import ( + "encoding/asn1" + "encoding/base64" + "fmt" + "github.com/google/trillian" + "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/maphasher" + "github.com/google/trillian/merkle/rfc6962" + "github.com/google/trillian/types" + "time" +) + +// Proof defines both a PoA and a Map PoP +type Proof struct { + MapID int64 `json:"map_id"` + Proof *trillian.MapLeafInclusion `json:"proof"` + Timestamp int64 `json:"timestamp"` + Signature Signature `json:"signature"` +} + +func (p *Proof) VerifyProof(root *types.MapRootV1) error { + return merkle.VerifyMapInclusionProof(p.MapID, p.Proof.Leaf, root.RootHash, p.Proof.Inclusion, maphasher.Default) +} + +// Returned by ILSes in GetPoA +type PoAResp struct { + PoA Proof `json:"poa"` + MultiSMR *MultiSignedMapRoot `json:"msmr"` +} + +// PoC from Trillian Log +type PoC struct { + Proof *trillian.Proof `json:"proof"` + Timestamp int64 `json:"timestamp"` + Signature Signature `json:"signature"` +} + +func (poc *PoC) VerifyProof(first, second uint64, firstHash, secondHash string) error { + prevHash, err := base64.StdEncoding.DecodeString(firstHash) + if err != nil { + return fmt.Errorf("failed to decode prev hash: %s", err) + } + + currHash, err := base64.StdEncoding.DecodeString(secondHash) + if err != nil { + return fmt.Errorf("failed to decode curr hash: %s", err) + } + + verifier := merkle.NewLogVerifier(rfc6962.DefaultHasher) + return verifier.VerifyConsistencyProof(int64(first), int64(second), prevHash, currHash, poc.Proof.Hashes) +} + +// Returned by ILSes in GetPoC +type PoCResp struct { + PoC PoC `json:"poc"` + MultiSLR *MultiSignedLogRoot `json:"mslr"` +} + +func MapLeafInclusionToString(p *trillian.MapLeafInclusion) string { + var out string + if len(p.Leaf.LeafValue) == 0 { + out += "" +} + +func MapRootV1ToString(p *types.MapRootV1) string { + return fmt.Sprintf("", p.RootHash, time.Unix(0, int64(p.TimestampNanos)), p.Revision) +} + +type signedMapRootDataType struct { + MapRoot []byte + Signature []byte +} + +func MarshalSignedMapRoot(p *trillian.SignedMapRoot) ([]byte, error) { + return asn1.Marshal(*p) +} + +func UnmarshalSignedMapRoot(data []byte, p *trillian.SignedMapRoot) error { + _, err := asn1.Unmarshal(data, p) + return err +} diff --git a/offlineauth/cyrill-k/trustflex/common/roots.go b/offlineauth/cyrill-k/trustflex/common/roots.go new file mode 100644 index 00000000..5f987e6e --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/roots.go @@ -0,0 +1,7 @@ +package common + +// Returned by ILSes during GetRoots +type MSRoots struct { + MSLR *MultiSignedLogRoot + MSMR *MultiSignedMapRoot +} \ No newline at end of file diff --git a/offlineauth/cyrill-k/trustflex/common/signatures.go b/offlineauth/cyrill-k/trustflex/common/signatures.go new file mode 100644 index 00000000..6c56ad8a --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/signatures.go @@ -0,0 +1,195 @@ +// This files contains some helper definitions and functions +// to deal with signatures. + +package common + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "encoding/asn1" + "encoding/json" + "fmt" + "github.com/google/certificate-transparency-go/tls" + "log" + "math/big" +) + +type Signature tls.DigitallySigned + +type Sig struct { + R, S *big.Int +} + +func (s *Sig) Convert(algo tls.SignatureAlgorithm, hashAlgorithm tls.HashAlgorithm) (Signature, error) { + var ds tls.DigitallySigned + var err error + ds.Signature, err = asn1.Marshal(*s) + + if err != nil { + return Signature(ds), fmt.Errorf("failed to marshal the signature: %s", err) + } + + ds.Algorithm.Hash = hashAlgorithm + ds.Algorithm.Signature = algo + return Signature(ds), nil +} + +func ConvertBack(signature Signature) (Sig, error) { + var sig Sig + rest, err := asn1.Unmarshal(signature.Signature, &sig) + + if err != nil { + return sig, fmt.Errorf("failed to unmarshal the signature: %s", err) + } + + if len(rest) > 0 { + return sig, fmt.Errorf("%d data found after signature", len(rest)) + } + + return sig, nil +} + +func TLSToCryptoHash(hashAlgorithm tls.HashAlgorithm) crypto.Hash { + switch hashAlgorithm { + case tls.MD5: + return crypto.MD5 + case tls.SHA1: + return crypto.SHA1 + case tls.SHA224: + return crypto.SHA224 + case tls.SHA256: + return crypto.SHA256 + case tls.SHA384: + return crypto.SHA384 + case tls.SHA512: + return crypto.SHA512 + default: + return 0 + } +} + +func StringToTLSHash(hashAlgo string) tls.HashAlgorithm{ + switch hashAlgo { + + case "MD5": + return tls.MD5 + case "SHA1": + return tls.SHA1 + case "SHA224": + return tls.SHA224 + case "SHA256": + return tls.SHA256 + case "SHA384": + return tls.SHA384 + case "SHA512": + return tls.SHA512 + default: + log.Fatalf("%s is not a supported hash algorithm", hashAlgo) + return tls.None + } +} + +func LoadPrivateKey(keyFile, sigAlgo string) interface{} { + bytePrivateKey, err := KeyFromPEM(keyFile) + LogError("Failed to read private key from file: %s", err) + + switch sigAlgo { + case "RSA": + privateKey, err := x509.ParsePKCS1PrivateKey(bytePrivateKey) + LogError("Failed to parse RSA private key: %s", err) + return *privateKey + case "ECDSA": + privateKey, err := x509.ParseECPrivateKey(bytePrivateKey) + LogError("Failed to parse ECDSA private key: %s", err) + return *privateKey + + default: + log.Fatalf("%s is not a supported signature algorithm", sigAlgo) + return nil + } +} + +func ComputeHash(algo tls.HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) { + hashType := TLSToCryptoHash(algo) + + if hashType == 0 { + return nil, hashType, fmt.Errorf("specified algorithm is not supported: %v", algo) + } + + hasher := hashType.New() + if _, err := hasher.Write(data); err != nil { + return nil, hashType, fmt.Errorf("failed to compute hash of data: %v", err) + } + return hasher.Sum([]byte{}), hashType, nil +} + +func VerifySignatures(eecert []*x509.Certificate, data []byte, signature Signature) error { + var err error + for idx, cert := range eecert { + err = tls.VerifySignature(cert.PublicKey, data, tls.DigitallySigned(signature)) + if err != nil { + return fmt.Errorf("signature %d verification failed", idx) + } + } + return nil +} + +// This is a separated method used to compute the signature of the updated root in BFT. +// Re-implemented since tls.VerifySignature() also compute the hash, which we already have +// since it is provided by Trillian when retrieving the latest root. +func (s *Signature) VerifySignature(pubKey crypto.PublicKey, data []byte) (bool, error) { + algorithm := s.Algorithm.Signature + switch algorithm { + + case tls.RSA: + pubKey, ok := pubKey.(*rsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot use %T to verify signature", pubKey) + } + + if err := rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, data, s.Signature); err != nil { + return false, fmt.Errorf("signature verification failed: %s", err) + } + + return true, nil + + case tls.ECDSA: + pubKey, ok := pubKey.(*ecdsa.PublicKey) + + if !ok { + return false, fmt.Errorf("cannot use %T to verify signature", pubKey) + } + + sig, err := ConvertBack(*s) + if err != nil { + return false, fmt.Errorf("failed to convert signature: %s", err) + } + + return ecdsa.Verify(pubKey, data, sig.R, sig.S), nil + + + default: + return false, fmt.Errorf("%T is not a valid or supported signature algoritm", algorithm) + } +} + +func Sign(privateKey crypto.PrivateKey, algorithm tls.HashAlgorithm, data interface{}) (tls.DigitallySigned, error) { + byteData, err := json.Marshal(data) + if err != nil { + return tls.DigitallySigned{}, fmt.Errorf("failed to marhsal data: %s", err) + } + + return tls.CreateSignature(privateKey, algorithm, byteData) +} + +func Verify(publicKey crypto.PublicKey, data interface{}, signature Signature) error { + byteData, err := json.Marshal(data) + if err != nil { + return fmt.Errorf("failed to marhsal data: %s", err) + } + + return tls.VerifySignature(publicKey, byteData, tls.DigitallySigned(signature)) +} diff --git a/offlineauth/cyrill-k/trustflex/common/x509util.go b/offlineauth/cyrill-k/trustflex/common/x509util.go new file mode 100644 index 00000000..1e271a6e --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/common/x509util.go @@ -0,0 +1,501 @@ +// Functions and definitions related to x509 + +package common + +import ( + "bytes" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + // "github.com/google/trillian/merkle/maphasher" +) + +// EECert extensions +var ( + OIDExtensionCALST = asn1.ObjectIdentifier{1, 3, 500, 1} + OIDExtensionILSLST = asn1.ObjectIdentifier{1, 3, 500, 2} + OIDExtensionCAMIN = asn1.ObjectIdentifier{1, 3, 500, 3} + OIDExtensionILSTO = asn1.ObjectIdentifier{1, 3, 500, 4} + OIDExtensionCATH = asn1.ObjectIdentifier{1, 3, 500, 5} + OIDExtensionCOPUNLKD = asn1.ObjectIdentifier{1, 3, 500, 6} + OIDExtensionCOPUNTRSTD = asn1.ObjectIdentifier{1, 3, 500, 7} + + OIDExtensionUNIQUE = asn1.ObjectIdentifier{1, 3, 500, 8} +) + +type X509BoolExtension struct { + Inherited bool + Value bool +} + +type JsonCAListExt struct { + CAList []string `json:"ca_list"` +} + +type JsonILSListExt struct { + ILSList []string `json:"ils_list"` +} + +func ResolvePolicy(domain string, certificates [][]x509.Certificate) (map[string]interface{}, error) { + policy := make(map[string]interface{}) + policy["UNIQUE"] = false + for _, c := range certificates { + for _, ext := range c[0].Extensions { + if ext.Id.Equal(OIDExtensionUNIQUE) { + if err := parseBoolExtension(domain, policy, "UNIQUE", &c[0], ext); err != nil { + return nil, fmt.Errorf("failed to unmarshal UNIQUE extension: %s", err) + } + } + } + } + return policy, nil +} + +func (e *X509BoolExtension) GetValue() []byte { + data, err := asn1.Marshal(*e) + if err != nil { + log.Fatalf("error marshalling %+v: %s", e, err) + } + return data +} + +func parseBoolExtension(domain string, policy map[string]interface{}, key string, certificate *x509.Certificate, ext pkix.Extension) error { + b := X509BoolExtension{} + _, err := asn1.Unmarshal(ext.Value, &b) + if err != nil { + return fmt.Errorf("failed to unmarshal bool extension: %s", err) + } + + // if the extension is not inherited, it should not be added to the policy if the subject and all SANs are parent domains + sameDomain := IsSameDomain(domain, certificate.Subject.CommonName) + for _, san := range certificate.DNSNames { + if IsSameDomain(domain, san) { + sameDomain = true + } + } + if b.Inherited || sameDomain { + policy[key] = b.Value + } + return nil +} + +func X509ParseCertificates(chainBytes []byte) (chain []x509.Certificate, err error) { + var pointerChain []*x509.Certificate + pointerChain, err = x509.ParseCertificates(chainBytes) + if err != nil { + return + } + for _, p := range pointerChain { + chain = append(chain, *p) + } + return +} + +// Read Public Key from file +func LoadPK(file string) (interface{}, error) { + content, err := ioutil.ReadFile(file) + + if err != nil { + LogError("Cannot read from "+file+": %s", err) + } + + block, _ := pem.Decode(content) + if block == nil { + return nil, errors.New("nil pem block") + } + + if block.Type == "PUBLIC KEY" { + return x509.ParsePKIXPublicKey(block.Bytes) + } else { + return nil, fmt.Errorf("file %s does not contain a public key", file) + } +} + +func WriteCertBytesToFile(certBytes []byte, f string) { + certOut, err := os.Create(f) + if err != nil { + log.Fatalf("Failed to open %s for writing: %s", f, err) + } + if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil { + log.Fatalf("Failed to write data to cert.pem: %s", err) + } + if err := certOut.Close(); err != nil { + log.Fatalf("Error closing cert.pem: %s", err) + } + log.Printf("wrote %s\n", f) +} + +// Read a PEM encoded private or public key from a +// given file +func KeyFromPEM(fileName string) ([]byte, error) { + var ret []byte + content, err := ioutil.ReadFile(fileName) + + if err != nil { + return nil, fmt.Errorf("failed to read from %s: %s", fileName, err) + } + + for { + var block *pem.Block + block, content = pem.Decode(content) + + if block == nil { + return nil, fmt.Errorf("no pem block in %s", fileName) + } + + if block.Type == "EC PRIVATE KEY" { + ret = block.Bytes + break + } else if block.Type == "PUBLIC KEY" { + ret = block.Bytes + break + } + } + + return ret, nil +} + +func ReadEECert(request *CRReq) (EECert, error) { + byteEECert := request.EECert + eecert, err := x509.ParseCertificates(byteEECert) + return eecert, err +} + +func CertFromFile(fileName string) (*x509.Certificate, error) { + byteCert, err := EECertFromPEM(fileName) + if err != nil { + return nil, fmt.Errorf("EECertFromPEM failed: %s", err) + } + + certificate, err := x509.ParseCertificate(byteCert) + if err != nil { + return nil, fmt.Errorf("failed to parse certificate: %s", err) + } + return certificate, nil +} + +func PubKeyFromCert(certificate *x509.Certificate) interface{} { + pubKey := certificate.PublicKey + return pubKey +} + +func X509CertToString(certificate *x509.Certificate) string { + return fmt.Sprintf("", DomainsFromX509Cert(certificate), certificate.SerialNumber) +} + +func X509CertChainToString(chain []x509.Certificate) string { + return fmt.Sprintf("", len(chain), chain[len(chain)-1].AuthorityKeyId, X509CertToString(&chain[0])) +} + +func X509CertChainToStringExtended(chain []x509.Certificate) string { + out := fmt.Sprintf("", x.Subject.String(), DomainsFromX509Cert(&x), x.SerialNumber, x.SubjectKeyId, x.AuthorityKeyId) + } + return out + ">" +} + +// Read an EECert from a given file. +// Iterate through multiple PEM blocks. +func EECertFromPEM(fileName string) (ByteEECert, error) { + var bytesCerts []byte + content, err := ioutil.ReadFile(fileName) + + if err != nil { + return nil, fmt.Errorf("failed to read %s: %s", fileName, err) + } + + for { + var block *pem.Block + block, content = pem.Decode(content) + + if block == nil { + if len(bytesCerts) == 0 { + return nil, fmt.Errorf("no pem block in %s", fileName) + } else { + return bytesCerts, nil + } + } + + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("%s contains data other than certificate", fileName) + } + + bytesCerts = append(bytesCerts, block.Bytes...) + } +} + +func X509CertChainBytesFromPEM(fileName string) ([]byte, error) { + var bytesCerts []byte + content, err := ioutil.ReadFile(fileName) + + if err != nil { + return nil, fmt.Errorf("failed to read %s: %s", fileName, err) + } + + for { + var block *pem.Block + block, content = pem.Decode(content) + + if block == nil { + if len(bytesCerts) == 0 { + return nil, fmt.Errorf("no pem block in %s", fileName) + } else { + return bytesCerts, nil + } + } + + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("%s contains data other than certificate", fileName) + } + + bytesCerts = append(bytesCerts, block.Bytes...) + } +} + +// Read an EECert from a given file. +// Iterate through multiple PEM blocks. +func X509CertFromPEM(fileName string) (*x509.Certificate, error) { + content, err := ioutil.ReadFile(fileName) + + if err != nil { + return nil, fmt.Errorf("failed to read %s: %s", fileName, err) + } + + var block *pem.Block + block, _ = pem.Decode(content) + + if block == nil { + return nil, fmt.Errorf("no pem block in %s", fileName) + } + + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("%s contains data other than certificate", fileName) + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + return cert, nil +} + +func DomainsFromX509Cert(cert *x509.Certificate) []string { + var domains []string + domains = append(domains, strings.ToLower(cert.Subject.CommonName)) + for _, d := range cert.DNSNames { + domains = append(domains, strings.ToLower(d)) + } + return domains +} + +func X509ContainsDomain(cert *x509.Certificate, domain string) bool { + for _, d := range DomainsFromX509Cert(cert) { + if d == domain { + return true + } + } + return false +} + +func X509MatchesDomain(cert *x509.Certificate, domain string) bool { + for _, d := range DomainsFromX509Cert(cert) { + if IsSameDomain(d, domain) { + return true + } + } + return false +} + +func MapKeysFromX509Cert(cert *x509.Certificate) [][]byte { + var mapKeys [][]byte + for _, d := range DomainsFromX509Cert(cert) { + mapKeys = append(mapKeys, []byte(d)) + } + return mapKeys +} + +// assume that cert[0] is endpoint certificate and cert[len(cert)-1] is certificate issued by CA and CA is in the system's certificate pool +func X509Verify(cert []x509.Certificate) ([][]*x509.Certificate, error) { + r, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + for _, c := range X509GetCerts("/home/cyrill/go/src/github.com/cyrill-k/trustflex/data", "ca\\d+_cert.pem") { + r.AddCert(c) + } + + // gradually add certs from chain and attempt to verify certificate + p := x509.NewCertPool() + var verifiedChains [][]*x509.Certificate + // if all verification attempts fail, return last error (i.e., error when attempting to verify with all non self-signed certificates) + var lastError error + succeeded := false + for _, x := range cert[1:] { + if !X509CertIsSelfSigned(x) { + //Debug("Adding intermediate certificate and verify: %s", X509CertToString(&x)) + p.AddCert(&x) + var newChains [][]*x509.Certificate + newChains, lastError = cert[0].Verify(x509.VerifyOptions{Intermediates: p, Roots: r}) + if lastError == nil && len(newChains) > 0 { + succeeded = true + verifiedChains = append(verifiedChains, newChains...) + // a single successful verification is enough + break + } + } + } + if succeeded { + return verifiedChains, nil + } else { + return nil, lastError + } +} + +func X509CertIsSelfSigned(c x509.Certificate) bool { + return len(c.AuthorityKeyId) == 0 || bytes.Compare(c.SubjectKeyId, c.AuthorityKeyId) == 0 +} + +func X509GetCerts(certFolder, regex string) []*x509.Certificate { + var certs []*x509.Certificate + + re, err := regexp.Compile(regex) + LogError("Failed to create regex: %s", err) + + err = filepath.Walk(certFolder, func(path string, info os.FileInfo, err error) error { + if re.Find([]byte(path)) != nil { + // log.Printf("%s, %d, %s, %s", path, info.Size(), err, re.Find([]byte(path))) + cert, err := X509CertFromPEM(path) + LogError("Failed to read cert from file: %s", err) + + certs = append(certs, cert) + } + return nil + }) + return certs +} + +// Used by both CAs and ILS during Certificate Update +func VerifyUpdateRequirements(old, new []*x509.Certificate, firstILS, firstCA, secondCA string) error { + log.Println("Verifying update requirements") + + var newCas JsonCAListExt + var newIls JsonILSListExt + var newMin int + var err error + for _, cert := range new { + newExts := cert.Extensions + + for _, ext := range newExts { + if ext.Id.Equal(OIDExtensionCALST) { + err := json.Unmarshal(ext.Value, &newCas.CAList) + + if err != nil { + return fmt.Errorf("failed to unmarshal CA list extension: %s", err) + } + + if !SliceIncludes(newCas.CAList, firstCA) || !SliceIncludes(newCas.CAList, firstCA) { + return errors.New("involved CAs are not in CA_LIST") + } + + } else if ext.Id.Equal(OIDExtensionILSLST) { + err := json.Unmarshal(ext.Value, &newIls.ILSList) + + if err != nil { + return fmt.Errorf("failed to unmarshal ILS list extension: %s", err) + } + + if !SliceIncludes(newIls.ILSList, firstILS) { + return fmt.Errorf("involved ILS is not in ILS_LIST: %s", firstILS) + } + + } else if ext.Id.Equal(OIDExtensionCAMIN) { + newMin, err = strconv.Atoi(string(ext.Value)) + + if err != nil { + return fmt.Errorf("failed to convert CA_MIN extension: %s", err) + } + + if len(new) < newMin { + return fmt.Errorf("EECert should have at least %d certificates, but only has %d", newMin, len(new)) + } + } + } + + } + var oldCas JsonCAListExt + var oldIls JsonILSListExt + var oldMin int + var oldCOP, oldCOPLKD int64 + for _, cert := range old { + oldExts := cert.Extensions + + for _, ext := range oldExts { + if ext.Id.Equal(OIDExtensionCALST) { + err := json.Unmarshal(ext.Value, &oldCas.CAList) + + if err != nil { + return fmt.Errorf("failed to unmarshal CA list extension: %s", err) + } + } else if ext.Id.Equal(OIDExtensionILSLST) { + err := json.Unmarshal(ext.Value, &oldIls.ILSList) + + if err != nil { + return fmt.Errorf("failed to unmarshal ILS list extension: %s", err) + } + + } else if ext.Id.Equal(OIDExtensionCAMIN) { + oldMin, err = strconv.Atoi(string(ext.Value)) + + if err != nil { + return fmt.Errorf("failed to convert CA_MIN extension: %s", err) + } + } else if ext.Id.Equal(OIDExtensionCOPUNTRSTD) { + oldCOP, err = strconv.ParseInt(string(ext.Value), 10, 64) + + if err != nil { + return fmt.Errorf("failed to convert COP_UNTRUSTED extension: %s", err) + } + } else if ext.Id.Equal(OIDExtensionCOPUNLKD) { + oldCOPLKD, err = strconv.ParseInt(string(ext.Value), 10, 64) + + if err != nil { + return fmt.Errorf("failed to convert COP_UNLINKED extension: %s", err) + } + } + } + } + + if !SliceIncludes(oldIls.ILSList, firstILS) || !SliceIncludes(oldCas.CAList, firstCA) || + !SliceIncludes(oldCas.CAList, secondCA) { + return fmt.Errorf("untrusted entities with respect to old EECert, cool-off period set to %d", oldCOP) + } + + if len(new) < oldMin { + return fmt.Errorf("new EECert should have at least %d (old CA_MIN) certificates, but only has %d", oldMin, len(new)) + } + + signedByOld := new[len(new)-1] // last certificate of new EECert is the one signed by the old private key + // public keys are the same, so take old[0] + err = signedByOld.CheckSignatureFrom(old[0]) + if err != nil { + return fmt.Errorf("failed to verify old EECert signature over new one, cool-off period set to %d: %s", oldCOPLKD, err) + } + + return nil +} diff --git a/offlineauth/cyrill-k/trustflex/rainsclientlog/logclient.go b/offlineauth/cyrill-k/trustflex/rainsclientlog/logclient.go new file mode 100644 index 00000000..96ad17a6 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/rainsclientlog/logclient.go @@ -0,0 +1,136 @@ +package rainsclientlog + +import ( + "crypto/x509" + "fmt" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/trillian/mapper" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/trillian/tclient" + "log" + "os" +) + +var maxReceiveMessageSize = 1073741824 +var First = true + +func QueryMapServerZoneInfo(zone string, mapID int64, LogAddr string, LogPkeyPath string) ([][]x509.Certificate, error) { + mapClient := tclient.NewMapClient(LogAddr, LogPkeyPath, maxReceiveMessageSize) + defer mapClient.Close() + + proofs, err := mapClient.GetProofForDomains(mapID, mapClient.GetMapPK(), []string{zone}) + common.LogError("Couldn't retrieve proofs for all domains: %s", err) + if err != nil { + return nil, err + } + + proof := proofs[0] + + if proof.GetDomain() == zone { + err := proof.Validate(mapID, mapClient.GetMapPK(), common.DefaultTreeNonce, zone) + if err != nil { + log.Printf("Entry %d (%s): Validate failed: %s", 0, proof.GetDomain(), err) + return nil, err + } + log.Printf("Entry %d (%s): %s", 0, proof.GetDomain(), proof.ToString()) + } else { + log.Printf("Proof for wrong zone: %s, expected: %s", proof.GetDomain(), zone) + return nil, err + } + certs := proof.GetUnrevokedCertificates(zone) + return certs, nil + +} + +func AddToLogServer(cert *x509.Certificate, logID int64, LogAddress string, LogPkeyPath string) { + logClient := tclient.NewLogClient(LogAddress, LogPkeyPath, maxReceiveMessageSize) + defer logClient.Close() + logClient.LogCert(cert, logID) +} + +func Mapping(MapPkeyPath string, MapID int64, MapAddress string, LogPkeyPath string, LogID int64, LogAddress string) error { + log.Printf("mapping %s", MapPkeyPath) + mper, err := mapper.NewMapper(MapAddress, MapPkeyPath, "logdata/valid.gob", "logdata/invalid.gob", "logdata/dropped.csv", maxReceiveMessageSize) + if err != nil { + common.LogError("Couldn't create mapper: %s", err) + return err + } + defer mper.Close() + + lastIdx := readLastIdx() + lastIdx, err = mper.PerformMapping(LogAddress, LogPkeyPath, LogID, MapID, lastIdx) + common.LogError("Mapping failed: %s", err) + return err +} + +func RevokeCert(cert *x509.Certificate, MapPkeyPath string, MapID int64, MapAddress string) { + mapClient := tclient.NewMapClient(MapAddress, MapPkeyPath, maxReceiveMessageSize) + defer mapClient.Close() + encodedMapEntries, err := mapClient.GetValues(MapID, mapClient.GetMapPK(), []string{cert.DNSNames[0]}, true, true) + common.LogError("Get Values failed: %s", err) + fmt.Println(encodedMapEntries) + + setmap := map[string]tclient.EncodedMapEntry{} + + for _, entry := range encodedMapEntries { + var existing tclient.MapEntryType + err = existing.UnmarshalBinary(entry.LeafValue) + + fmt.Println("Get Map Entry to Revoke Cert: ", existing.ToString()) + revocations := existing.GetRevocations() + for _, rev := range revocations { + fmt.Println(string(rev.GetMessage()), rev.GetRevokedSerialNumber()) + } + certificates := existing.GetCertificates() + + var chainleafs[]x509.Certificate + for _, chain := range certificates { + chainleafs = append(chainleafs, chain[0]) + } + + var certToRevoke *x509.Certificate + for _, logcert := range chainleafs { + if logcert.Equal(cert) { + certToRevoke = &logcert + } + } + + if certToRevoke == nil { + fmt.Println("WARNING: Cert to revoke not found in Log") + } else { + existing.Revocations = append(existing.Revocations, tclient.RevocationMessageType{ + SerialNumber: *certToRevoke.SerialNumber, + Message: []byte("Revoked"), + }) + leafValue, err := existing.MarshalBinary() + if err != nil { + common.LogError("Failed to Marshal Binary: %s", err) + } else { + entry.LeafValue = leafValue + setmap[cert.DNSNames[0]] = *entry + break + } + + } + } + + err = mapClient.SetValues(MapID, mapClient.GetMapPK(), setmap, true) + common.LogError("Failed to set new values: %s", err) + +} + + +func readLastIdx() int64 { + var lastIdx int64 + lastIdx = 0 + if !First { + file, _ := os.Open("trillian/lastIdx") + // common.LogError("Failed to open lastIdx file: %s", err) + defer file.Close() + + _, _ = fmt.Fscanf(file, "%d", &lastIdx) + // common.LogError("Failed reading lastIdx: %s", err) + } else { + //First = false // TODO investigate why sometimes not updating mapping when this is used + } + return lastIdx +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/mapper/mapper.go b/offlineauth/cyrill-k/trustflex/trillian/mapper/mapper.go new file mode 100644 index 00000000..d0d21ea3 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/mapper/mapper.go @@ -0,0 +1,598 @@ +// This file holds Mapper-related code. +// The Mapper is responsible for mapping +// EECerts from the Log to the Map. +// The current implementation does not use +// this anymore, since the BFT already +// add the certificates to both the Map and the Log. + +package mapper + +import ( + "bufio" + "context" + "crypto" + "crypto/x509" + "fmt" + "github.com/golang/protobuf/ptypes" + ct "github.com/google/certificate-transparency-go" + ctclient "github.com/google/certificate-transparency-go/client" + "github.com/google/certificate-transparency-go/jsonclient" + "github.com/google/trillian" + "github.com/google/trillian/client" + "github.com/google/trillian/client/rpcflags" + "github.com/google/trillian/crypto/keyspb" + "github.com/google/trillian/crypto/sigpb" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/trillian/tclient" + "google.golang.org/grpc" + "log" + "os" + "strings" + "time" +) + +type TrillianMapper interface { + PerformMappingFromCTLog(ctLogAddress string, mapID int64, lastIdx int64, endIdx int64, batchSize int64) (int64, error) + PerformMapping(logAddress string, logPk string, logID, mapID int64, lastIdx int64) (int64, error) + PerformMappingFromProofs(proofs []tclient.Proof, mapID int64, batchSize int64) error + ValidDomains() map[string]bool + InvalidDomains() map[string]bool + Close() +} + +type trillianMapper struct { + MapClient tclient.MapClient + ValidDomainsFile, InvalidDomainsFile string + validDomains, invalidDomains map[string]bool + DroppedLogEntryWriter *common.DroppedLogEntryWriter + maxReceiveMessageSize int +} + +func NewMapper(mapAddress, mapPk string, validDomainsFile, invalidDomainsFile string, droppedLogEntryFile string, maxReceiveMessageSize int) (TrillianMapper, error) { + mapClient := tclient.NewMapClient(mapAddress, mapPk, maxReceiveMessageSize) + + f, err := common.OpenOrCreate(droppedLogEntryFile) + if err != nil { + return nil, fmt.Errorf("Can't open dropped log entry file: %s", err) + } + + mapper := trillianMapper{MapClient: mapClient, ValidDomainsFile: validDomainsFile, InvalidDomainsFile: invalidDomainsFile, DroppedLogEntryWriter: common.NewDroppedLogEntryWriter(bufio.NewWriter(f)), maxReceiveMessageSize: maxReceiveMessageSize} + err = mapper.readDomainsFromFile() + if err != nil { + return nil, fmt.Errorf("Error reading domains from file (%s,%s): %s", mapper.ValidDomainsFile, mapper.InvalidDomainsFile, err) + } + + return &mapper, nil +} + +type recursiveMapEntry struct { + mapEntry *tclient.MapEntryType + subdomains map[string]*recursiveMapEntry +} + +func (tm *trillianMapper) ValidDomains() map[string]bool { + return tm.validDomains +} + +func (tm *trillianMapper) InvalidDomains() map[string]bool { + return tm.invalidDomains +} + +func (tm *trillianMapper) readDomainsFromFile() error { + if err := common.GobReadMapBool(tm.ValidDomainsFile, &tm.validDomains); err != nil { + return err + } + if err := common.GobReadMapBool(tm.InvalidDomainsFile, &tm.invalidDomains); err != nil { + return err + } + return nil +} + +func (tm *trillianMapper) writeDomainsToFile() error { + if err := common.GobWriteMapBool(tm.ValidDomainsFile, tm.validDomains); err != nil { + return err + } + if err := common.GobWriteMapBool(tm.InvalidDomainsFile, tm.invalidDomains); err != nil { + return err + } + return nil +} + +func (tm *trillianMapper) getBatchEntries(ctClient *ctclient.LogClient, ctx context.Context, lastIdx int64, batchSize int64) (logEntries []ct.LogEntry, dropped []common.DroppedLogEntry) { + var err error + logEntries, err = ctClient.GetEntries(ctx, lastIdx, lastIdx+batchSize-1) + if err == nil { + // for i := 0; i < len(logEntries); i++ { + // logEntryIndices = append(logEntryIndices, int64(lastIdx+i)) + // } + } else { + for i := int64(0); i < batchSize; i++ { + singleLogEntry, err := ctClient.GetEntries(ctx, lastIdx+i, lastIdx+i) + if err != nil { + dropped = append(dropped, common.DroppedLogEntry{CtLogIndex: lastIdx + i, Error: err}) + } else { + logEntries = append(logEntries, singleLogEntry[0]) + // logEntryIndices = append(logEntryIndices, lastIdx+i) + } + } + } + return +} + +func (tm *trillianMapper) PerformMappingFromCTLog(ctLogAddress string, mapID int64, lastIdx int64, endIdx int64, batchSize int64) (int64, error) { + ctClient, err := ctclient.New(ctLogAddress, nil, jsonclient.Options{}) + if err != nil { + return lastIdx, fmt.Errorf("Failed to create CT client: %v", err) + } + + // log write domains to disk + defer func() { + err := tm.writeDomainsToFile() + if err != nil { + log.Printf("Error writing domains from file (%s,%s): %s", tm.ValidDomainsFile, tm.InvalidDomainsFile, err) + } + }() + + ctx := context.Background() + for { + logEntries, batchDropped := tm.getBatchEntries(ctClient, ctx, lastIdx, batchSize) + for _, d := range batchDropped { + tm.DroppedLogEntryWriter.Write(&d) + } + // nEntries := batchSize + // // Get the entries from the log: + // logEntries, err := ctClient.GetEntries(ctx, lastIdx, common.Min(lastIdx+batchSize, endIdx)) + // if err != nil { + // return lastIdx, dropped, fmt.Errorf("Failed to retrieve entries from CT log: %s", err) + // } + // if len(logEntries) == 0 { + // return lastIdx, dropped, fmt.Errorf("No entries from log") + // } + common.Log("Retrieved [%d, %d] from %s; Failed %d", lastIdx, lastIdx+batchSize, ctLogAddress, len(batchDropped)) + + var certs [][]x509.Certificate + for _, entry := range logEntries { + if entry.Leaf.LeafType != ct.TimestampedEntryLeafType { + tm.DroppedLogEntryWriter.Write(&common.DroppedLogEntry{ + CtLogIndex: entry.Index, + Error: fmt.Errorf("Skipping unknown entry type %v at %d", entry.Leaf.LeafType, entry.Index)}) + continue + } + switch entry.Leaf.TimestampedEntry.EntryType { + case ct.X509LogEntryType: + cert, err := x509.ParseCertificate(entry.Leaf.TimestampedEntry.X509Entry.Data) + if err != nil { + tm.DroppedLogEntryWriter.Write(&common.DroppedLogEntry{ + CtLogIndex: entry.Index, + Error: fmt.Errorf("Can't parse certificate at index %d: %s", entry.Index, err)}) + continue + } + chainWithoutRootCert := []x509.Certificate{*cert} + for i, asn1Cert := range entry.Chain { + if i+1 < len(entry.Chain) { + //don't store root certificate + chainCert, err := x509.ParseCertificate(asn1Cert.Data) + if err != nil { + tm.DroppedLogEntryWriter.Write(&common.DroppedLogEntry{ + CtLogIndex: entry.Index, + Error: fmt.Errorf("Failed to parse certificate chain at %d for %s: %s", i, common.X509CertToString(cert), err)}) + break + } + chainWithoutRootCert = append(chainWithoutRootCert, *chainCert) + } + } + if len(entry.Chain) == len(chainWithoutRootCert) { + // only add certificate if the chain could be parsed + certs = append(certs, chainWithoutRootCert) + } + // cert, err := x509.ParseCertificate(entry.Leaf.TimestampedEntry.X509Entry.Data) + // if err != nil { + // glog.Warningf("Can't parse cert at index %d, continuing anyway because this is a toy", entry.Index) + // continue + // } + // updateDomainMap(domains, *cert, entry.Index, false) + case ct.PrecertLogEntryType: + tm.DroppedLogEntryWriter.Write(&common.DroppedLogEntry{ + CtLogIndex: entry.Index, + Error: fmt.Errorf("Ignoring precertificate")}) + // common.Log("Ignoring precertificate") + // precert, err := x509.ParseTBSCertificate(entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate) + // if err != nil { + // glog.Warningf("Can't parse precert at index %d, continuing anyway because this is a toy", entry.Index) + // continue + // } + // updateDomainMap(domains, *precert, entry.Index, true) + default: + tm.DroppedLogEntryWriter.Write(&common.DroppedLogEntry{ + CtLogIndex: entry.Index, + Error: fmt.Errorf("Ignoring unknown logentry type at index %d", entry.Index)}) + } + } + + newLastIdx, err := tm.performMapping(certs, mapID, lastIdx, lastIdx+int64(len(logEntries)+len(batchDropped)), true) + if err != nil { + return lastIdx, err + } + lastIdx = newLastIdx + if newLastIdx >= endIdx { + common.Log("Finished mapping at %d", lastIdx) + return lastIdx, nil + } + } + return lastIdx, nil +} + +// Map Log content to the Map, starting from lastIdx +func (tm *trillianMapper) PerformMapping(logAddress string, logPk string, logID, mapID int64, lastIdx int64) (int64, error) { + logClient := tclient.NewLogClient(logAddress, logPk, tm.maxReceiveMessageSize) + defer logClient.Close() + // Get new certificates from log server + logLeaves := logClient.RetrieveCerts(logID, lastIdx) + if len(logLeaves) == 0 { + return lastIdx, fmt.Errorf("No new logLeaves to map") + } + var certs [][]x509.Certificate + for _, leaf := range logLeaves { + cert, err := common.X509ParseCertificates(leaf.LeafValue) + if err != nil { + return lastIdx, fmt.Errorf("Failed to parse leaves from CT log: %s", err) + } + certs = append(certs, cert) + } + + // log write domains to disk + defer func() { + err := tm.writeDomainsToFile() + if err != nil { + log.Printf("Error writing domains from file (%s,%s): %s", tm.ValidDomainsFile, tm.InvalidDomainsFile, err) + } + }() + return tm.performMapping(certs, mapID, lastIdx, lastIdx+int64(len(logLeaves)), true) +} + +func (tm *trillianMapper) PerformMappingFromProofs(proofs []tclient.Proof, mapID int64, batchSize int64) error { + for i := 0; i < len(proofs); i++ { + common.Debug("Mapping Proofs[%d,%d] ...", i, common.Min(int64(len(proofs)), int64(i)+batchSize)) + pBatch := proofs[i:common.Min(int64(len(proofs)), int64(i)+batchSize)] + var batchCerts [][]x509.Certificate + for _, p := range pBatch { + batchCerts = append(batchCerts, p.GetAllCertificates()...) + } + _, err := tm.performMapping(batchCerts, mapID, 0, 0, false) + if err != nil { + return fmt.Errorf("Couldn't perform mapping from proofs[%d,%d]: %s", i, common.Min(int64(len(proofs)), int64(i)+batchSize), err) + } + common.Debug("Finished mapping proofs[%d,%d]", i, common.Min(int64(len(proofs)), int64(i)+batchSize)) + } + return nil +} + +func (tm *trillianMapper) performMapping(certificates [][]x509.Certificate, mapID int64, lastIdx int64, newLastIdx int64, updateLastIdx bool) (int64, error) { + // Extract map entries and generate [domain -> map entry] map + recursiveMapEntries, validDomains, invalidDomains, err := extractMapEntries(certificates) + if err != nil { + return lastIdx, fmt.Errorf("Failed to extract map entries from certificates: %s", err) + } + // log add domains + for _, d := range validDomains { + tm.validDomains[d] = true + } + for _, d := range invalidDomains { + tm.invalidDomains[d] = true + } + // printRecursiveSubdomains(recursiveMapEntries, 0, 2) + e2LDdomains := make([]string, len(recursiveMapEntries)) + i := 0 + for k := range recursiveMapEntries { + e2LDdomains[i] = k + i++ + } + + // create mock recursiveMapEntry with mapEntry = nil then call getsubdomaintreeroot on it + globalREntry := &recursiveMapEntry{mapEntry: nil, subdomains: recursiveMapEntries} + globalRootHash, err := tm.getSubdomainTreeRoot(globalREntry, mapID, tm.MapClient.GetMapPK(), "") + if err != nil { + return lastIdx, err + } + common.Debug("global root hash = %+v", globalRootHash) + + if updateLastIdx { + common.Debug("Mapping performed, last leaf index: %d\n", newLastIdx) + writeLastIdx(newLastIdx) + } + return newLastIdx, nil +} + +// currentDomain is only used for debugging/logging purposes +func (tm *trillianMapper) getSubdomainTreeRoot(entry *recursiveMapEntry, mapID int64, mapPK crypto.PublicKey, currentDomain string) ([]byte, error) { + verify := mapPK != nil + + // Find (sub-)domains that are being updated + domains := make([]string, len(entry.subdomains)) + i := 0 + for k := range entry.subdomains { + domains[i] = k + i++ + } + + // Get map entries for these domains + common.Debug("Fetching existing entries from mapID=%d for %s ...", mapID, currentDomain) + // perform the merkle hash (inclusion) verification but don't check the signature if we don't have the map's public key + encodedMapEntries, err := tm.MapClient.GetValues(mapID, mapPK, domains, verify, true) + if err != nil { + return nil, fmt.Errorf("Couldn't fetch values from map server to perform mapping: %s", err) + } + count := 0 + for _, e := range encodedMapEntries { + if len(e.LeafValue) > 0 { + count += 1 + } + } + common.Debug("Fetched %d non-empty entries", count) + + // Merge new and existing certificates and encode + rEntries := entry.subdomains + mergedMapEntries := make(map[string]tclient.EncodedMapEntry) + for i, domain := range domains { + rEntry := rEntries[domain] + // subdomain status variables + var hasSubdomains bool + var subtreeRoot []byte + var subtreeId int64 + + // used for debugging + var d string + if currentDomain == "" { + d = domain + } else { + d = domain + "." + currentDomain + } + common.Debug("Processing %s ...", d) + + // domain already exists + if len(encodedMapEntries[i].LeafValue) > 0 { + common.Debug("Updating existing entry") + // unmarshal existing entry + var existing tclient.MapEntryType + err = existing.UnmarshalBinary(encodedMapEntries[i].LeafValue) + if err != nil { + return nil, fmt.Errorf("Couldn't unmarshal map entry data %s", err) + } + + // merge entries + common.Debug("Before merge: new=%+v, existing=%+v", rEntry.mapEntry.ToString(), existing.ToString()) + rEntry.mapEntry.Merge(&existing) + common.Debug("After merge: new=%+v", rEntry.mapEntry.ToString()) + + // keep existing subdomains if not changed by update + hasSubdomains = encodedMapEntries[i].HasSubdomains + copy(subtreeRoot, existing.SubtreeRoot) + subtreeId = encodedMapEntries[i].SubdomainTreeId + } + + // if this update affects subdomains + if len(rEntry.subdomains) > 0 { + common.Debug("Updating subdomains") + // create map tree if it does not exist yet + if !hasSubdomains { + common.Debug("Creating anonymous map tree...") + var err error + subtreeId, err = createAnonymousMapTree(tm.MapClient.GetMapAddress()) + if err != nil { + return nil, fmt.Errorf("Couldn't create anonymous map tree: %s", err) + } + common.Debug("Created anonymous map tree with mapID=%d", subtreeId) + } + hasSubdomains = true + + // recursively build map trees for subdomains + subtreeRoot, err = tm.getSubdomainTreeRoot(rEntry, subtreeId, nil, d) + if err != nil { + return nil, fmt.Errorf("Error in domain %d: %s", d, err) + } + } + rEntry.mapEntry.SubtreeRoot = subtreeRoot + + // marshal merged entries + leafValue, err := rEntry.mapEntry.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("Couldn't marshal entry to binary: %s", err) + } + + mergedMapEntries[domain] = tclient.EncodedMapEntry{LeafValue: leafValue, HasSubdomains: hasSubdomains, SubdomainTreeId: subtreeId} + } + + // Set merged map entries + err = tm.MapClient.SetValues(mapID, mapPK, mergedMapEntries, verify) + if err != nil { + return nil, fmt.Errorf("Failed to set key:value pairs in map server: %s", err) + } + + // retrieve MHT root hash + root, err := tm.MapClient.GetMapRoot(mapID, mapPK, false) + if err != nil { + return nil, fmt.Errorf("Failed to get map root: %s", err) + } + common.Debug("Returning update root hash (%x) for domain %s and subtreeId=%d", root.RootHash, currentDomain, mapID) + return root.RootHash, nil +} + +func extractMapEntries(certificates [][]x509.Certificate) (map[string]*recursiveMapEntry, []string, []string, error) { + mapEntries := make(map[string]*recursiveMapEntry) + var validDomains, invalidDomains []string + for _, cert := range certificates { + for _, domain := range common.DomainsFromX509Cert(&cert[0]) { + if !common.IsViableDomain(domain) { + invalidDomains = append(invalidDomains, domain) + continue + } + + s, err := common.SplitE2LD(domain) + if err != nil { + invalidDomains = append(invalidDomains, domain) + continue + // return nil, validDomains, invalidDomains, fmt.Errorf("Couldn't split '%s' into subdomains: %s", domain, err) + } + + validDomains = append(validDomains, domain) + + // reverse to start at E2LD + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + + var entry, oldEntry *recursiveMapEntry + for i, d := range s { + var quitLoop bool + // read entry + if i == 0 { + if _, ok := mapEntries[d]; !ok { + mapEntries[d] = &recursiveMapEntry{subdomains: make(map[string]*recursiveMapEntry)} + } + entry = mapEntries[d] + } else { + oldEntry = entry + if _, ok := entry.subdomains[d]; !ok { + entry.subdomains[d] = &recursiveMapEntry{subdomains: make(map[string]*recursiveMapEntry)} + } + entry = entry.subdomains[d] + } + + if entry.mapEntry == nil { + entry.mapEntry = &tclient.MapEntryType{} + } + // update entry + var add tclient.MapEntryType + if i == len(s)-1 { + add.Certificates = append(add.Certificates, cert) + } else if i == len(s)-2 && common.IsWildcardLabel(s[len(s)-1]) { + add.WildcardCertificates = append(add.WildcardCertificates, cert) + quitLoop = true + } + entry.mapEntry.Merge(&add) + + // write entry + if i == 0 { + mapEntries[d] = entry + } else { + oldEntry.subdomains[d] = entry + } + + if quitLoop { + break + } + } + } + } + return mapEntries, validDomains, invalidDomains, nil +} + +func printRecursiveSubdomains(r map[string]*recursiveMapEntry, indent, indentStep int) { + if len(r) == 0 { + return + } + for domain, entry := range r { + var nCerts, nWildcardCerts int + if entry.mapEntry != nil { + nCerts = len(entry.mapEntry.Certificates) + nWildcardCerts = len(entry.mapEntry.WildcardCertificates) + } + log.Printf("%s%s: %d certs, %d wildcard certs", strings.Repeat(" ", indent), domain, nCerts, nWildcardCerts) + printRecursiveSubdomains(entry.subdomains, indent+indentStep, indentStep) + } +} + +func createAnonymousMapTree(adminServerAddress string) (int64, error) { + ts, ok := trillian.TreeState_value[trillian.TreeState_ACTIVE.String()] + if !ok { + return 0, fmt.Errorf("unknown TreeState: %v", trillian.TreeState_ACTIVE.String()) + } + + tt, ok := trillian.TreeType_value[trillian.TreeType_MAP.String()] + if !ok { + return 0, fmt.Errorf("unknown TreeType: %v", trillian.TreeType_MAP.String()) + } + + hs, ok := trillian.HashStrategy_value[trillian.HashStrategy_TEST_MAP_HASHER.String()] + if !ok { + return 0, fmt.Errorf("unknown HashStrategy: %v", trillian.HashStrategy_TEST_MAP_HASHER.String()) + } + + ha, ok := sigpb.DigitallySigned_HashAlgorithm_value[sigpb.DigitallySigned_SHA256.String()] + if !ok { + return 0, fmt.Errorf("unknown HashAlgorithm: %v", sigpb.DigitallySigned_SHA256.String()) + } + + sa, ok := sigpb.DigitallySigned_SignatureAlgorithm_value[sigpb.DigitallySigned_ECDSA.String()] + if !ok { + return 0, fmt.Errorf("unknown SignatureAlgorithm: %v", sigpb.DigitallySigned_ANONYMOUS.String()) + } + + maxDuration, err := time.ParseDuration("0") + common.LogError("Couldn't parse zero duration: %s", err) + + //TODO(cyrill) clean up the above mess and directly set correct values + req := &trillian.CreateTreeRequest{Tree: &trillian.Tree{ + TreeState: trillian.TreeState(ts), + TreeType: trillian.TreeType(tt), + HashStrategy: trillian.HashStrategy(hs), + HashAlgorithm: sigpb.DigitallySigned_HashAlgorithm(ha), + SignatureAlgorithm: sigpb.DigitallySigned_SignatureAlgorithm(sa), + DisplayName: "", + Description: "", + MaxRootDuration: ptypes.DurationProto(maxDuration), + }} + + //TODO(cyrill) how can we not generate a key for anonymous (no) signing? + req.KeySpec = &keyspb.Specification{} + + switch sigpb.DigitallySigned_SignatureAlgorithm(sa) { + case sigpb.DigitallySigned_ECDSA: + req.KeySpec.Params = &keyspb.Specification_EcdsaParams{ + EcdsaParams: &keyspb.Specification_ECDSA{}, + } + case sigpb.DigitallySigned_RSA: + req.KeySpec.Params = &keyspb.Specification_RsaParams{ + RsaParams: &keyspb.Specification_RSA{}, + } + default: + log.Fatalf("unsupported signature algorithm: %v", sa) + } + + dialOpts, err := rpcflags.NewClientDialOptionsFromFlags() + if err != nil { + return 0, fmt.Errorf("failed to determine dial options: %v", err) + } + + conn, err := grpc.Dial(adminServerAddress, dialOpts...) + if err != nil { + return 0, fmt.Errorf("failed to dial %v: %v", adminServerAddress, err) + } + defer conn.Close() + + adminClient := trillian.NewTrillianAdminClient(conn) + mapClient := trillian.NewTrillianMapClient(conn) + logClient := trillian.NewTrillianLogClient(conn) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + tree, err := client.CreateAndInitTree(ctx, req, adminClient, mapClient, logClient) + common.LogError("Failed to create tree: %s", err) + + return tree.TreeId, nil +} + +func writeLastIdx(lastIdx int64) { + file, err := os.Create("trillian/lastIdx") + common.LogError("Failed to create lastIdx file: %s", err) + defer file.Close() + + _, err = file.WriteString(fmt.Sprintf("%d", lastIdx)) + common.LogError("Failed writing lastIdx to file: %s", err) + +} + +func (tm *trillianMapper) Close() { + tm.MapClient.Close() + tm.DroppedLogEntryWriter.Close() +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/log_client.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/log_client.go new file mode 100644 index 00000000..fbb4c974 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/log_client.go @@ -0,0 +1,353 @@ +// LogClient provides functions to perform operations on a Trillian Log. + +package tclient + +import ( + "context" + "crypto" + "crypto/sha256" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + ct "github.com/google/certificate-transparency-go" + "github.com/google/trillian" + tcrypto "github.com/google/trillian/crypto" + "github.com/google/trillian/types" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "io/ioutil" + "log" +) + +type LogClient interface { + LogEECerts(logID int64, domains []string, op string) + LogCertFromFile(logID int64, fileName string) + LogCert(cert *x509.Certificate, logID int64) + RetrieveCerts(logID, lastIdx int64) []*trillian.LogLeaf + RetrieveSignedLogRoot(logID int64) *types.LogRootV1 + GetPoP(logID int64, domain string) (*trillian.Proof, *types.LogRootV1, error) + GetPoC(logID, first, second int64) (*trillian.Proof, *types.LogRootV1, error) + GetEntriesByRange(logID, start, count int64) ([]*trillian.LogLeaf, error) + Close() +} + +type logClient struct { + connection *grpc.ClientConn + client trillian.TrillianLogClient + logPK crypto.PublicKey +} + +// To avoid import cycle +func logError(msg string, err error) { + if err != nil { + log.Printf(msg, err) + } +} + +// Create a new LogClient +func NewLogClient(address, logPk string, maxReceiveMessageSize int) LogClient { + log.Println("Opening Connection to Trillian Log at " + address + "...") + g, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithMaxMsgSize(maxReceiveMessageSize)) + logError("Failed connecting to Trillian log at "+address+": %s", err) + log.Println("Connection Opened") + + client := trillian.NewTrillianLogClient(g) + + pubKey, err := common.LoadPK(logPk) + logError("Failed to load public key: %s", err) + + tlClient := logClient{connection: g, client: client, logPK: pubKey} + return &tlClient +} + +// Log multiple (op, domain) pairs to the given Log +func (tc *logClient) LogEECerts(logID int64, domains []string, op string) { + log.Printf("Contacting Log to add %d EECerts to the tree...", len(domains)) + + var leaf *trillian.LogLeaf + var code codes.Code + var resp *trillian.QueueLeafResponse + var l *trillian.QueuedLogLeaf + var err error + + client := tc.client + for idx, domain := range domains { + leafValue := fmt.Sprintf("(%s, %s)", op, domain) + leaf = &trillian.LogLeaf{LeafValue: []byte(leafValue)} + qlReq := &trillian.QueueLeafRequest{LogId: logID, Leaf: leaf} + + resp, err = client.QueueLeaf(context.Background(), qlReq) + logError("Failed receiving response from log: %s", err) + + l = resp.QueuedLeaf + code = codes.Code(l.GetStatus().GetCode()) + if code != codes.OK && code != codes.AlreadyExists { + log.Fatalf("Bad return status %d: %v:", idx, l.GetStatus()) + } + + log.Printf("...EECert %d queued, (status, leaf index): (%v, %d)", idx, code, l.Leaf.LeafIndex) + } +} + +// Retrieve multiple leaves from the given log, starting from lastIdx +func (tc *logClient) RetrieveCerts(logID, lastIdx int64) []*trillian.LogLeaf { + client := tc.client + ctx := context.Background() + + desRoot := tc.RetrieveSignedLogRoot(logID) + + log.Println("Tree size:", desRoot.TreeSize) + // log.Printf("hash %s", base64.StdEncoding.EncodeToString(desRoot.RootHash)) + var leaves []*trillian.LogLeaf + log.Println("Retrieving Certs...") + + var i uint64 + if lastIdx == 0 { + i = 0 + } else { + i = uint64(lastIdx) + 1 + } + + for i < desRoot.TreeSize { + gReq := &trillian.GetLeavesByRangeRequest{LogId: logID, StartIndex: int64(i), Count: 10} + resp, err := client.GetLeavesByRange(ctx, gReq) + logError("Failed getting leaves by range: %s", err) + + leaves = append(leaves, resp.Leaves...) + log.Println("Received", len(resp.Leaves), "leaves") + var currentLeaf *trillian.LogLeaf + for j := 0; j < len(resp.Leaves); j++ { + currentLeaf = resp.Leaves[j] + cert, err := common.X509ParseCertificates(currentLeaf.LeafValue) + logError("Couldn't unmarshal certificate from asn1: %s", err) + log.Printf("Leaf %d (value, leafidentityhash, merkleleafhash): %s %x %x", currentLeaf.LeafIndex, common.X509CertChainToString(cert), currentLeaf.LeafIdentityHash, currentLeaf.MerkleLeafHash) + i++ + } + } + log.Println("Certs retrieved:", len(leaves)) + return leaves +} + +// Fetch a Log PoP +func (tc *logClient) GetPoP(logID int64, domain string) (*trillian.Proof, *types.LogRootV1, error) { + desRoot := tc.RetrieveSignedLogRoot(logID) // should return err + leaf := fmt.Sprintf("(add, %s)", domain) + prefixedHash := append([]byte{ct.TreeLeafPrefix}, []byte(leaf)...) + leafHash := sha256.Sum256(prefixedHash) + + popReq := trillian.GetInclusionProofByHashRequest{ + LogId: logID, + LeafHash: leafHash[:], + TreeSize: int64(desRoot.TreeSize), + } + + log.Println("Getting Proof of Presence...") + popRsp, err := tc.client.GetInclusionProofByHash(context.Background(), &popReq) + + if err != nil { + return nil, nil, fmt.Errorf("failed to get PoP: %s", err) + } + + if popRsp.Proof[0].String() == "" { + return nil, nil, errors.New("empty PoP received") + } + + for idx, node := range popRsp.Proof[0].Hashes { + if len(node) != sha256.Size { + return nil, nil, fmt.Errorf("inconsistent size for node %d", idx) + } + } + + log.Println("...done") + return popRsp.Proof[0], desRoot, nil + +} + +// Fetch a PoC +func (tc *logClient) GetPoC(logID, first, second int64) (*trillian.Proof, *types.LogRootV1, error) { + log.Printf("Retrieving PoC between tree sizes %d, %d", first, second) + + req := trillian.GetConsistencyProofRequest{ + LogId: logID, + FirstTreeSize: first, + SecondTreeSize: second, + } + + resp, err := tc.client.GetConsistencyProof(context.Background(), &req) + if err != nil { + return nil, &types.LogRootV1{}, fmt.Errorf("failed to get PoC: %s", err) + } + + currentRoot := tc.RetrieveSignedLogRoot(logID) + if currentRoot.TreeSize < uint64(second) { + return nil, &types.LogRootV1{}, fmt.Errorf("current root tree size %d < provided second tree size %d", currentRoot.TreeSize, second) + } + + if !checkPath(resp.Proof.Hashes) { + return nil, &types.LogRootV1{}, fmt.Errorf("trillian log returned invalid PoC: %v", resp.Proof) + } + + return resp.Proof, currentRoot, nil + +} + +// Retrieve count leaves starting from start, from the given Log +func (tc *logClient) GetEntriesByRange(logID, start, count int64) ([]*trillian.LogLeaf, error) { + log.Printf("Retrieving %d entries starting from %d", count, start) + + req := trillian.GetLeavesByRangeRequest{ + LogId: logID, + StartIndex: start, + Count: count, + } + + resp, err := tc.client.GetLeavesByRange(context.Background(), &req) + if err != nil { + return nil, fmt.Errorf("failed to GetLeavesByRange: %s", err) + } + + currentRoot := tc.RetrieveSignedLogRoot(logID) + if currentRoot.TreeSize <= uint64(start) { + return nil, fmt.Errorf("tree size %d is < than start %d", currentRoot.TreeSize, start) + } + + if len(resp.Leaves) > int(count) { + return nil, fmt.Errorf("too many leaves: asked %d, returned %d", count, len(resp.Leaves)) + } + + for i, leaf := range resp.Leaves { + if leaf.LeafIndex != start+int64(i) { + return nil, fmt.Errorf("unexpected leaf index %d at index %d", leaf.LeafIndex, i) + } + } + + return resp.Leaves, nil +} + +// Retrieve the latest Signed Log Root +func (tc *logClient) RetrieveSignedLogRoot(logID int64) *types.LogRootV1 { + log.Println("Retrieving latest SLR...") + tlrReq := &trillian.GetLatestSignedLogRootRequest{LogId: logID} + tlRoot, err := tc.client.GetLatestSignedLogRoot(context.Background(), tlrReq) + logError("Could not retrieve Trillian SLR: %s", err) + log.Println("...done") + + log.Println("Verifying root signature...") + desRoot, err := tcrypto.VerifySignedLogRoot(tc.logPK, 5, tlRoot.SignedLogRoot) + logError("Failed to verify log root signature: %s", err) + log.Println("...succeeded") + + return desRoot +} + +func (tc *logClient) Close() { + tc.connection.Close() +} + +func checkPath(path [][]byte) bool { + for _, node := range path { + if len(node) != sha256.Size { + return false + } + } + return true +} + +func checkRespCode(resp *trillian.QueueLeafResponse) codes.Code { + code := codes.Code(resp.QueuedLeaf.GetStatus().GetCode()) + if code != codes.OK && code != codes.AlreadyExists { + log.Fatal("Bad return status:", resp.QueuedLeaf.GetStatus()) + } + + return code +} + +func eeCertFromPEM(fileName string) []byte { + var bytesCerts []byte + content, err := ioutil.ReadFile(fileName) + + logError("Failed to read specified file: %s", err) + + for { + var block *pem.Block + block, content = pem.Decode(content) + + if block == nil { + return bytesCerts + } + + if block.Type != "CERTIFICATE" { + log.Fatal("Block contains data other than certificates.") + } + + bytesCerts = append(bytesCerts, block.Bytes...) + } +} + +func byteCertFromPEM(fileName string) []byte { + content, err := ioutil.ReadFile(fileName) + logError("Failed to read specified file: %s", err) + + block, _ := pem.Decode(content) + if block == nil { + log.Fatalf("Failed to decode certificate: '%s'", content) + } + if block.Type != "CERTIFICATE" { + log.Fatal("Block contains data other than certificates.") + } + + return block.Bytes +} + +/* FUNCTIONS USED ONLY BY trillian/main.go */ + +func (tc *logClient) LogCert(cert *x509.Certificate, logID int64) { + log.Println("Contacting Log to add " + cert.DNSNames[0] + " to the tree...") + leafValue := cert.Raw + + client := tc.client + + tlLeaf := &trillian.LogLeaf{LeafValue: leafValue} + qlReq := &trillian.QueueLeafRequest{LogId: logID, Leaf: tlLeaf} + + resp, err := client.QueueLeaf(context.Background(), qlReq) + logError("Failed receiving response from log: %s", err) + + code := checkRespCode(resp) + log.Printf("cert queued, (status, leaf index): (%v, %d)", code, resp.QueuedLeaf.Leaf.LeafIndex) +} + +func (tc *logClient) LogCertFromFile(logID int64, fileName string) { + log.Println("Contacting Log to add " + fileName + " to the tree...") + leafValue, err := leafValueFromCertificateFile(fileName) + logError("Failed to prepare Leaf Value to log: %s", err) + + client := tc.client + + tlLeaf := &trillian.LogLeaf{LeafValue: leafValue} + qlReq := &trillian.QueueLeafRequest{LogId: logID, Leaf: tlLeaf} + + resp, err := client.QueueLeaf(context.Background(), qlReq) + logError("Failed receiving response from log: %s", err) + + code := checkRespCode(resp) + log.Printf("cert queued, (status, leaf index): (%v, %d)", code, resp.QueuedLeaf.Leaf.LeafIndex) +} + +func leafValueFromCertificateFile(fileName string) ([]byte, error) { + certBytes, err := common.X509CertChainBytesFromPEM(fileName) + if err != nil { + return nil, err + } + + return certBytes, nil + + // data, err := asn1.Marshal(cert) + // if err != nil { + // return nil, err + // } + + // return data, nil +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/map_client.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_client.go new file mode 100644 index 00000000..e92d7119 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_client.go @@ -0,0 +1,264 @@ +// MapClient provides functions to perform operations on a Trillian Map + +package tclient + +import ( + "context" + "crypto" + "encoding/asn1" + "fmt" + "github.com/google/trillian" + tcrypto "github.com/google/trillian/crypto" + "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/maphasher" + "github.com/google/trillian/types" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "google.golang.org/grpc" + "log" + "time" +) + +type EncodedMapEntry struct { + LeafValue []byte + HasSubdomains bool + SubdomainTreeId int64 +} + +type MapClient interface { + GetValues(mapID int64, mapPK crypto.PublicKey, domainRequests []string, verifyRootSignature bool, verifyInclusionProof bool) ([]*EncodedMapEntry, error) + SetValues(mapID int64, mapPK crypto.PublicKey, leaves map[string]EncodedMapEntry, verifyRootSignature bool) error + GetProofForDomains(mapID int64, mapPK crypto.PublicKey, domains []string) ([]Proof, error) + GetMapRoot(mapID int64, mapPK crypto.PublicKey, verify bool) (*types.MapRootV1, error) + GetMapPK() crypto.PublicKey + GetMapAddress() string + Close() +} + +type mapClient struct { + connection *grpc.ClientConn + client trillian.TrillianMapClient + mapPK crypto.PublicKey + treeNonce []byte + mapAddress string +} + +// Create a new MapClient +func NewMapClient(mapAddress, mapPk string, maxReceiveMessageSize int) MapClient { + log.Println("Opening Connection to Trillian Map at " + mapAddress + "...") + conn, err := grpc.Dial(mapAddress, grpc.WithInsecure(), grpc.WithMaxMsgSize(maxReceiveMessageSize)) + logError("Failed connecting to Trillian Map at "+mapAddress+":%s", err) + log.Println("Connection Opened") + + client := trillian.NewTrillianMapClient(conn) + + pubKey, err := common.LoadPK(mapPk) + logError("Failed to parse public key: %s", err) + + mapClient := mapClient{connection: conn, client: client, mapPK: pubKey, treeNonce: common.DefaultTreeNonce, mapAddress: mapAddress} + return &mapClient +} + +// get leaves from the given Map +func (mc *mapClient) GetValues(mapID int64, mapPK crypto.PublicKey, domainRequests []string, verifyRootSignature bool, verifyInclusionProof bool) ([]*EncodedMapEntry, error) { + encodedMapEntries, _, err := mc.getValuesWithInclusionProof(mapID, mapPK, domainRequests, verifyRootSignature, verifyInclusionProof) + return encodedMapEntries, err +} + +// Add new leaves to the given Map +func (mc *mapClient) SetValues(mapID int64, mapPK crypto.PublicKey, leaves map[string]EncodedMapEntry, verifyRootSignature bool) error { + var mapLeaves []*trillian.MapLeaf + for k, v := range leaves { + key := mc.mapKeyFromDomain(k) + common.Debug("mapclient.SetValues(%s -> %x)", k, key) + var extraData []byte + if v.HasSubdomains { + var err error + extraData, err = asn1.Marshal(v.SubdomainTreeId) + common.LogError("Couldn't marshal the subdomain's tree id: %s", err) + } + mapLeaves = append(mapLeaves, &trillian.MapLeaf{Index: key, LeafValue: v.LeafValue, ExtraData: extraData}) + } + req := trillian.SetMapLeavesRequest{MapId: mapID, Leaves: mapLeaves} + + ctx := context.Background() + common.Debug("Setting %d key:value pairs...\n", len(mapLeaves)) + + resp, err := mc.client.SetLeaves(ctx, &req) + if err != nil { + return fmt.Errorf("failed setting leaves: %s", err) + } + + _, err = extractMapRoot(resp.MapRoot, mapPK, verifyRootSignature) + return err +} + +// get hierarchical proof composed of inclusion proofs for each subdomain for the given domains +func (mc *mapClient) GetProofForDomains(mapID int64, mapPK crypto.PublicKey, domains []string) ([]Proof, error) { + var proofs []Proof + for _, domain := range domains { + p, err := mc.getProofForDomain(mapID, mapPK, domain) + if err != nil { + return proofs, err + } + proofs = append(proofs, p) + } + return proofs, nil +} + +func (mc *mapClient) GetMapRoot(mapID int64, mapPK crypto.PublicKey, verify bool) (*types.MapRootV1, error) { + signedMapRoot, err := mc.getSignedMapRoot(mapID, mapPK) + if err != nil { + return nil, err + } + + root, err := extractMapRoot(signedMapRoot, mapPK, verify) + if err != nil { + return root, fmt.Errorf("Couldn't extract map root mapID=%d, mapPK=%+v, verify=%t: %s", mapID, mapPK, verify, err) + } + + return root, nil +} + +func (mc *mapClient) GetMapPK() crypto.PublicKey { + return mc.mapPK +} + +func (mc *mapClient) GetMapAddress() string { + return mc.mapAddress +} + +func (mc *mapClient) mapKeyFromDomain(domain string) []byte { + return common.GenerateMapKey(mc.treeNonce, domain) +} + +func (mc *mapClient) getProofForDomain(mapID int64, mapPK crypto.PublicKey, domain string) (Proof, error) { + labels, err := common.SplitE2LD(domain) + fmt.Println("labels: ", labels) + if err != nil { + return nil, fmt.Errorf("Couldn't split into subdomains: %s", err) + } + + // reverse to start at E2LD + for i, j := 0, len(labels)-1; i < j; i, j = i+1, j-1 { + labels[i], labels[j] = labels[j], labels[i] + } + + var mapEntries []proofMapEntryType + var inclusionProofs []InclusionProofType + var signedMapRoot *trillian.SignedMapRoot + + signedMapRoot, err = mc.getSignedMapRoot(mapID, mapPK) + if err != nil { + return nil, err + } + + for _, label := range labels { + if label == "*" { + break + } + fmt.Println("get inclusion proof for: ", label) + encodedMapEntries, inc, err := mc.getValuesWithInclusionProof(mapID, mapPK, []string{label}, false, false) + if err != nil { + return nil, err + } + mapID = encodedMapEntries[0].SubdomainTreeId + mapPK = nil + + var entry proofMapEntryType + leafValue := encodedMapEntries[0].LeafValue + if len(leafValue) > 0 { + err := entry.UnmarshalBinary(leafValue) + if err != nil { + return nil, err + } + } + entry.SetDomain(label) + + mapEntries = append(mapEntries, entry) + inclusionProofs = append(inclusionProofs, inc[0]) + + if len(entry.GetSubtreeRoot()) == 0 { + break + } + } + + return &proofType{mapEntries: mapEntries, inclusionProofs: inclusionProofs, signedMapRoot: *signedMapRoot}, nil +} + +func (mc *mapClient) getValuesWithInclusionProof(mapID int64, mapPK crypto.PublicKey, domainRequests []string, verifyRootSignature bool, verifyInclusionProof bool) ([]*EncodedMapEntry, []InclusionProofType, error) { + common.Debug("Requesting map entries for %d (sub-)domains: %s", len(domainRequests), domainRequests) + var keys [][]byte + for _, domain := range domainRequests { + keys = append(keys, mc.mapKeyFromDomain(domain)) + } + mapLeaves, inclusionProofs, _, err := getLeaves(mapID, keys, mc.client, mapPK, verifyRootSignature, verifyInclusionProof) + + var encodedMapEntries []*EncodedMapEntry + for _, mapLeaf := range mapLeaves { + var hasSubdomains bool + var subdomainTreeId int64 + if len(mapLeaf.ExtraData) != 0 { + _, err := asn1.Unmarshal(mapLeaf.ExtraData, &subdomainTreeId) + if err != nil { + return nil, nil, fmt.Errorf("Couldn't unmarshal the subdomain's tree id: %s", err) + } + hasSubdomains = true + } + encodedMapEntries = append(encodedMapEntries, &EncodedMapEntry{LeafValue: mapLeaf.LeafValue, HasSubdomains: hasSubdomains, SubdomainTreeId: subdomainTreeId}) + } + return encodedMapEntries, inclusionProofs, err +} + +func getLeaves(mapID int64, keys [][]byte, client trillian.TrillianMapClient, mapPK crypto.PublicKey, + verifyRootSignature bool, verifyInclusionProof bool) ([]*trillian.MapLeaf, []InclusionProofType, *types.MapRootV1, error) { + + req := &trillian.GetMapLeavesRequest{MapId: mapID, Index: keys} + + ctx := context.Background() + resp, err := client.GetLeaves(ctx, req) + if err != nil { + return nil, nil, &types.MapRootV1{}, err + } + + var mapLeaves []*trillian.MapLeaf + var inclusionProofs []InclusionProofType + root, err := extractMapRoot(resp.MapRoot, mapPK, verifyRootSignature) + if err != nil { + return nil, nil, root, err + } + for _, proof := range resp.MapLeafInclusion { + mapLeaves = append(mapLeaves, proof.Leaf) + inclusionProofs = append(inclusionProofs, proof.Inclusion) + if verifyInclusionProof && merkle.VerifyMapInclusionProof(mapID, proof.Leaf, root.RootHash, proof.Inclusion, maphasher.Default) != nil { + return mapLeaves, inclusionProofs, root, fmt.Errorf("Invalid inclusion proof: mapID = %x, leaf = %+v, root = %x, inclusion = %+v", mapID, proof.Leaf, root.RootHash, proof.Inclusion) + } + } + return mapLeaves, inclusionProofs, root, nil +} + +func (mc *mapClient) Close() { + mc.connection.Close() +} + +func (mc *mapClient) getSignedMapRoot(mapID int64, mapPK crypto.PublicKey) (*trillian.SignedMapRoot, error) { + req := &trillian.GetSignedMapRootRequest{MapId: mapID} + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + resp, err := mc.client.GetSignedMapRoot(ctx, req) + if err != nil { + return nil, err + } + + return resp.MapRoot, nil +} + +func extractMapRoot(signedRoot *trillian.SignedMapRoot, mapPK crypto.PublicKey, verify bool) (*types.MapRootV1, error) { + if verify { + return tcrypto.VerifySignedMapRoot(mapPK, 5, signedRoot) + } else { + var root types.MapRootV1 + err := root.UnmarshalBinary(signedRoot.MapRoot) + return &root, err + } +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry.go new file mode 100644 index 00000000..9e260398 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry.go @@ -0,0 +1,349 @@ +// A MapEntry stores certificates valid for a specific (wildcard-)domain and possibly the root of a tree for subdomains + +package tclient + +import ( + "bytes" + "crypto/x509" + "encoding" + "encoding/asn1" + "fmt" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "math/big" +) + +type RevocationMessage interface { + // Returns nil if the revocation message (the embedded signature) is valid + Validate() error + + GetMessage() []byte + GetRevokedSerialNumber() big.Int +} + +type MapEntry interface { + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler + ToString() string + + GetCertificates() [][]x509.Certificate + GetRevocations() []RevocationMessage + GetWildcardCertificates() [][]x509.Certificate + GetWildcardRevocations() []RevocationMessage + GetSubtreeRoot() []byte +} + +type RevocationMessageType struct { + SerialNumber big.Int + Message []byte +} + +type revocationMessageDataType struct { + SerialNumber []byte + Message []byte +} + +type MapEntryType struct { + // domain under which the map entry is stored in the map (is not encoded into the binary representation) + domain string + // the first certificate in the chain is the endpoint certificate and the last certificate is the certificate issued by a root certificate + Certificates [][]x509.Certificate + Revocations []RevocationMessageType + WildcardCertificates [][]x509.Certificate + WildcardRevocations []RevocationMessageType + SubtreeRoot []byte +} + +type mapEntryDataType struct { + Certificates [][]byte + Revocations [][]byte + WildcardCertificates [][]byte + WildcardRevocations [][]byte + SubtreeRoot []byte +} + +func (me *RevocationMessageType) GetMessage() []byte { + return me.Message +} + +func (me *RevocationMessageType) GetRevokedSerialNumber() big.Int { + return me.SerialNumber +} + +func (me *RevocationMessageType) Validate() error { + //TODO(cyrill) implement signature checking + signature algorithm + return nil +} + +func (me *MapEntryType) Merge(other *MapEntryType) { + mergeCertificates(&me.Certificates, other.Certificates) + mergeRevocationMessages(&me.Revocations, other.Revocations) + mergeCertificates(&me.WildcardCertificates, other.WildcardCertificates) + mergeRevocationMessages(&me.WildcardRevocations, other.WildcardRevocations) +} + +func mergeCertificates(l1 *[][]x509.Certificate, l2 [][]x509.Certificate) { + for _, e2 := range l2 { + // common.Debug("Checking if %d: %s already exists ...", j, common.X509CertChainToString(e2)) + add := true + for _, e1 := range *l1 { + if len(e1) == len(e2) { + i := 0 + for ; i < len(e1); i++ { + if !bytes.Equal(e1[i].Raw, e2[i].Raw) { + // common.Debug("Found different cert in chain at %d: %s", i, common.X509CertToString(&e2[i])) + break + } + } + if i == len(e1) { + // common.Debug("Not adding %s", common.X509CertChainToString(e2)) + add = false + break + } + } + } + if add { + // common.Debug("Adding %s", common.X509CertChainToString(e2)) + *l1 = append(*l1, e2) + } + } +} + +func mergeRevocationMessages(l1 *[]RevocationMessageType, l2 []RevocationMessageType) { + for _, e2 := range l2 { + add := true + for _, e1 := range *l1 { + if bytes.Equal(e1.Message, e2.Message) && (&e1.SerialNumber).Cmp(&e2.SerialNumber) == 0 { + add = false + break + } + } + if add { + *l1 = append(*l1, e2) + } + } +} + +func (me *MapEntryType) MarshalBinary() (data []byte, err error) { + var d mapEntryDataType + for _, c := range me.Certificates { + var chain []byte + for _, x := range c { + chain = append(chain, x.Raw...) + } + d.Certificates = append(d.Certificates, chain) + } + + for _, r := range me.Revocations { + rmd := revocationMessageDataType{SerialNumber: r.SerialNumber.Bytes(), Message: r.Message} + revocationBytes, err := asn1.Marshal(rmd) + if err != nil { + return nil, fmt.Errorf("Couldn't marshal revocation: %s", err) + } + d.Revocations = append(d.Revocations, revocationBytes) + } + + for _, c := range me.WildcardCertificates { + var chain []byte + for _, x := range c { + chain = append(chain, x.Raw...) + } + d.WildcardCertificates = append(d.WildcardCertificates, chain) + } + + for _, r := range me.WildcardRevocations { + rmd := revocationMessageDataType{SerialNumber: r.SerialNumber.Bytes(), Message: r.Message} + revocationBytes, err := asn1.Marshal(rmd) + if err != nil { + return nil, fmt.Errorf("Couldn't marshal wildcard revocation: %s", err) + } + d.WildcardRevocations = append(d.WildcardRevocations, revocationBytes) + } + + //copy(d.SubtreeRoot, me.SubtreeRoot) + d.SubtreeRoot = me.SubtreeRoot + + return asn1.Marshal(d) +} + +func (me *MapEntryType) UnmarshalBinary(data []byte) error { + me.Certificates = nil + me.WildcardCertificates = nil + me.Revocations = nil + me.WildcardRevocations = nil + + var d mapEntryDataType + _, err := asn1.Unmarshal(data, &d) + if err != nil { + return fmt.Errorf("Couldn't unmarshal mapEntryDataType: %s", err) + } + + for _, cBytes := range d.Certificates { + c, err := x509.ParseCertificates(cBytes) + if err != nil { + return fmt.Errorf("Couldn't parse x509 certificate: %s", err) + } + var chain []x509.Certificate + for _, x := range c { + chain = append(chain, *x) + } + me.Certificates = append(me.Certificates, chain) + } + + for _, cBytes := range d.WildcardCertificates { + c, err := x509.ParseCertificates(cBytes) + if err != nil { + return fmt.Errorf("Couldn't parse x509 certificate: %s", err) + } + var chain []x509.Certificate + for _, x := range c { + chain = append(chain, *x) + } + me.WildcardCertificates = append(me.WildcardCertificates, chain) + } + + for _, rBytes := range d.Revocations { + var rmd revocationMessageDataType + _, err := asn1.Unmarshal(rBytes, &rmd) + var s big.Int + s.SetBytes(rmd.SerialNumber) + r := RevocationMessageType{SerialNumber: s, Message: rmd.Message} + if err != nil { + return fmt.Errorf("Couldn't parse revocation message: %s", err) + } + me.Revocations = append(me.Revocations, r) + } + + for _, rBytes := range d.WildcardRevocations { + var rmd revocationMessageDataType + _, err := asn1.Unmarshal(rBytes, &rmd) + var s big.Int + s.SetBytes(rmd.SerialNumber) + r := RevocationMessageType{SerialNumber: s, Message: rmd.Message} + if err != nil { + return fmt.Errorf("Couldn't parse revocation message: %s", err) + } + me.WildcardRevocations = append(me.WildcardRevocations, r) + } + + //copy(me.SubtreeRoot, d.SubtreeRoot) + me.SubtreeRoot = d.SubtreeRoot + + return nil +} + +type certLogFunction func(*[]x509.Certificate) string +type revocationLogFunction func(*RevocationMessageType) string + +func (me *MapEntryType) toString(cLog certLogFunction, rLog revocationLogFunction) string { + output := "" +} + +func (me *MapEntryType) ToString() string { + return me.toString( + func(c *[]x509.Certificate) string { return common.X509CertChainToString(*c) }, + func(r *RevocationMessageType) string { return r.SerialNumber.Text(10) }) +} + +func (me *MapEntryType) SetDomain(domain string) { + me.domain = domain +} + +func (me *MapEntryType) GetCertificates() [][]x509.Certificate { + return me.Certificates +} + +func (me *MapEntryType) GetRevocations() []RevocationMessage { + var out []RevocationMessage + for _, m := range me.Revocations { + out = append(out, &m) + } + return out +} + +func (me *MapEntryType) GetWildcardCertificates() [][]x509.Certificate { + return me.WildcardCertificates +} + +func (me *MapEntryType) GetWildcardRevocations() []RevocationMessage { + var out []RevocationMessage + for _, m := range me.WildcardRevocations { + out = append(out, &m) + } + return out +} + +func (me *MapEntryType) GetSubtreeRoot() []byte { + return me.SubtreeRoot +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry_test.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry_test.go new file mode 100644 index 00000000..49d8ff22 --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/map_entry_test.go @@ -0,0 +1,208 @@ +// A MapEntry stores certificates valid for a specific (wildcard-)domain and possibly the root of a tree for subdomains + +package tclient + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "fmt" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "log" + "math/big" + "net" + "os" + "strings" + "testing" + "time" +) + +func TestMapEntryTypeMarshal(t *testing.T) { + c := testCreateCertificate() + if c == nil { + t.Errorf("Couldn't create test certificate") + } + + r := []byte{1, 2, 3, 4} + in := MapEntryType{Certificates: [][]x509.Certificate{[]x509.Certificate{*c}}, WildcardCertificates: nil, Revocations: nil, WildcardRevocations: nil, SubtreeRoot: r} + testEntry(t, in) + + r2 := []byte{} + in2 := MapEntryType{Certificates: [][]x509.Certificate{[]x509.Certificate{*c}}, WildcardCertificates: nil, Revocations: nil, WildcardRevocations: nil, SubtreeRoot: r2} + testEntry(t, in2) +} + +func testEntry(t *testing.T, in MapEntryType) { + inEncoded, err := in.MarshalBinary() + if err != nil { + t.Errorf("Couldn't marshal MapEntryType: %s", err) + } + var out MapEntryType + err = out.UnmarshalBinary(inEncoded) + if err != nil { + t.Errorf("Couldn't unmarshal MapEntryType: %s", err) + } + if !testMapEntryTypeIsEqual(in, out) { + t.Errorf("MapEntryType changed after marshal/unmarshal: %+v != %+v: %s", in.ToString(), out.ToString(), err) + } +} + +func testCreateCertificate() *x509.Certificate { + priv, _ := GenerateKeys() + d := CreateCertificate(priv, PublicKey(priv), nil, strings.Split("CH,Example,ZH,www.example.ch", ",")) + c, err := x509.ParseCertificate(d) + if err != nil { + return nil + } + return c +} + +func testMapEntryTypeIsEqual(a, b MapEntryType) bool { + if len(a.Certificates) != len(b.Certificates) { + return false + } + if len(a.WildcardCertificates) != len(b.WildcardCertificates) { + return false + } + if len(a.Revocations) != len(b.Revocations) { + return false + } + if len(a.WildcardRevocations) != len(b.WildcardRevocations) { + return false + } + if len(a.SubtreeRoot) != len(b.SubtreeRoot) { + return false + } + + for i, _ := range a.Certificates { + if len(a.Certificates[i]) != len(b.Certificates[i]) { + return false + } + for j, _ := range a.Certificates[i] { + if (a.Certificates[i][j].SerialNumber).Cmp(b.Certificates[i][j].SerialNumber) != 0 { + return false + } + } + } + for i, _ := range a.WildcardCertificates { + if len(a.WildcardCertificates[i]) != len(b.WildcardCertificates[i]) { + return false + } + for j, _ := range a.WildcardCertificates[i] { + if (a.WildcardCertificates[i][j].SerialNumber).Cmp(b.WildcardCertificates[i][j].SerialNumber) != 0 { + return false + } + } + } + for i, ai := range a.Revocations { + if (&ai.SerialNumber).Cmp(&b.Revocations[i].SerialNumber) != 0 { + return false + } + } + for i, ai := range a.WildcardRevocations { + if (&ai.SerialNumber).Cmp(&b.WildcardRevocations[i].SerialNumber) != 0 { + return false + } + } + if !bytes.Equal(a.SubtreeRoot, b.SubtreeRoot) { + return false + } + return true +} + +func PublicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func CreateCertificate(priv_signer, pub_signee interface{}, caCert *x509.Certificate, subj []string) []byte { + notBefore := time.Now() + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + log.Fatalf("failed to generate serial number: %s", err) + } + + d, err := time.ParseDuration("1h") + if err != nil { + log.Fatalf("couldn't parse duration: %s", err) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Country: append([]string{}, subj[0]), + Organization: append([]string{}, subj[1]), + Locality: append([]string{}, subj[2]), + CommonName: subj[3], + }, + NotBefore: notBefore, + NotAfter: notBefore.Add(d), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := strings.Split("localhost", ",") + for _, h := range hosts { + if h == "" { + // do not add empty domains + } else if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + if true { + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + } + + var derBytes []byte + if true { + derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, pub_signee, priv_signer) + common.LogError("Failed to create self signed certificate: %s", err) + } else { + derBytes, err = x509.CreateCertificate(rand.Reader, &template, caCert, pub_signee, priv_signer) + common.LogError("Failed to create certificate: %s", err) + } + + return derBytes +} + +func GenerateKeys() (interface{}, error) { + var priv interface{} + var err error + switch "P256" { + case "": + priv, err = rsa.GenerateKey(rand.Reader, 4000) + case "P224": + priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + case "P256": + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case "P384": + priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + case "P521": + priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + + default: + fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", "P256") + os.Exit(1) + } + if err != nil { + log.Fatalf("failed to generate private key: %s", err) + } + return priv, err +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/proof.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/proof.go new file mode 100644 index 00000000..0dcd67ed --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/proof.go @@ -0,0 +1,621 @@ +// A ProofEntry stores map entries and inclusion proofs necessary to validate the proof chain + +package tclient + +import ( + "bufio" + "bytes" + "compress/flate" + "crypto" + "crypto/x509" + "encoding" + "encoding/asn1" + "fmt" + "github.com/robinburkhard/rainsdeleg/cyrill-k/trustflex/common" + "github.com/google/trillian" + "github.com/google/trillian/merkle" + "github.com/google/trillian/merkle/maphasher" + "io" + "log" + "strings" +) + +type InclusionProofType [][]byte + +type Proof interface { + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler + // returns true if the inclusion proof at the last level (excluding wildcard level) is a non-empty leaf + IsProofOfPresence() bool + SetEnableCompression(enable bool) + + // Set the domain for which this proof is valid; if split using common.SplitE2LD(), must return len(mapEntries) labels (only used for debugging purposes, domain provided in Validate() is used for validation) + SetDomain(domain string) error + // Get the full domain name (only used for debugging purposes, domain provided in Validate() is used for validation) + GetDomain() string + + // Returns in how many inclusion proofs is the proof split into (excluding wildcard level) + GetNumberOfEntries() int + // Return the entry at a specific level, where 0 is the effective second-level domain + GetEntry(level int) MapEntry + // Verify the validity of the proof + Validate(mapID int64, mapPK crypto.PublicKey, treeNonce []byte, domain string) error + GetUnrevokedCertificatesSignedByCAs(domain string, caAuthorityKeyIdentifiers [][]byte) [][]x509.Certificate + GetUnrevokedCertificates(domain string) [][]x509.Certificate + GetAllCertificates() [][]x509.Certificate + ToString() string + GetInclusionProofSize() (int, error) +} + +func NewProof() Proof { + return &proofType{} +} + +type proofMapEntryType struct { + MapEntryType + mapID int64 +} + +type proofType struct { + enableCompression bool + mapEntries []proofMapEntryType + // contains a slice of hashes for each entry with the corresponding hashes + inclusionProofs []InclusionProofType + signedMapRoot trillian.SignedMapRoot +} + +type proofDataType struct { + MapEntries [][]byte + InclusionProofs [][]byte + SignedMapRoot []byte +} + +func (p *proofType) SetEnableCompression(enable bool) { + p.enableCompression = enable +} + +func (p *proofType) GetInclusionProofSize() (int, error) { + var inclusionProofs [][]byte + for _, ip := range p.inclusionProofs { + data, err := ip.MarshalBinary() + if err != nil { + return 0, err + } + inclusionProofs = append(inclusionProofs, data) + } + d, err := asn1.Marshal(inclusionProofs) + if err != nil { + return 0, err + } + return len(d), nil +} + +func (p *proofType) GetUnrevokedCertificates(domain string) [][]x509.Certificate { + return p.getUnrevokedCertificates(domain, func(c []x509.Certificate) error { + return nil + }) +} + +func (p *proofType) GetUnrevokedCertificatesSignedByCAs(domain string, caAuthorityKeyIdentifiers [][]byte) [][]x509.Certificate { + return p.getUnrevokedCertificates(domain, func(c []x509.Certificate) error { + if isSignedByCAs(c, caAuthorityKeyIdentifiers) { + return nil + } + return fmt.Errorf("%s is not signed by trusted CA", common.X509CertChainToString(c)) + }) +} + +// http://thrtle.com +func (p *proofType) getUnrevokedCertificates(domain string, f func([]x509.Certificate) error) [][]x509.Certificate { + var certs [][]x509.Certificate + for _, e := range p.mapEntries { + for _, c := range e.Certificates { + if _, err := common.X509Verify(c); err != nil { + common.Debug("%s cannot be verified: %s", common.X509CertChainToString(c), err) + break + } + if err := f(c); err != nil { + common.Debug(err.Error()) + break + } + if isRevoked(c, e.Revocations) { + common.Debug("%s is revoked", common.X509CertChainToString(c)) + break + } + domains := common.DomainsFromX509Cert(&c[0]) + for i, d := range domains { + if common.IsDomainContainedIn(domain, d) { + if !containsCertificateChain(certs, c) { + certs = append(certs, c) + } else { + // common.Debug("%s is already added", common.X509CertChainToString(c)) + } + break + } + if i == len(domains)-1 { + common.Debug("%s was not added since none of its domains is contained in %s", common.X509CertChainToString(c), domain) + } + } + } + for _, c := range e.WildcardCertificates { + if _, err := common.X509Verify(c); err != nil { + common.Debug("%s cannot be verified: %s", common.X509CertChainToString(c), err) + break + } + if err := f(c); err != nil { + common.Debug(err.Error()) + break + } + if isRevoked(c, e.WildcardRevocations) { + common.Debug("%s is revoked", common.X509CertChainToString(c)) + break + } + domains := common.DomainsFromX509Cert(&c[0]) + for i, d := range domains { + if common.IsDomainContainedIn(domain, d) { + if !containsCertificateChain(certs, c) { + certs = append(certs, c) + } else { + // common.Debug("%s is already added", common.X509CertChainToString(c)) + } + break + } + if i == len(domains)-1 { + common.Debug("%s was not added since none of its domains is contained in %s", common.X509CertChainToString(c), domain) + } + } + } + } + return certs +} + +func (p *proofType) GetAllCertificates() (certs [][]x509.Certificate) { + for _, e := range p.mapEntries { + for _, c := range e.Certificates { + certs = append(certs, c) + } + } + return +} + +func containsCertificateChain(certList [][]x509.Certificate, cert []x509.Certificate) bool { + for _, c := range certList { + if len(c) == len(cert) { + for i, _ := range c { + if !bytes.Equal(c[i].Raw, cert[i].Raw) { + break + } + if i == len(c)-1 { + return true + } + } + } + } + return false +} + +func isSignedByCAs(c []x509.Certificate, caAuthorityKeyIdentifiers [][]byte) bool { + for _, caAKI := range caAuthorityKeyIdentifiers { + // if the CA certificate is not added in the certificate chain, the certificate issued by the CA must have its authority key id set (RFC5280, Section 4.2.1.1) + if bytes.Equal(c[len(c)-1].AuthorityKeyId, caAKI) { + return true + } + // if the CA certificate is added in the certificate chain, the CA certificate must have its subject key id set (RFC5280, Section 4.2.1.2) + if bytes.Equal(c[len(c)-1].SubjectKeyId, caAKI) { + return true + } + } + return false +} + +func isRevoked(c []x509.Certificate, revocations []RevocationMessageType) bool { + for _, x := range c { + for _, r := range revocations { + if r.SerialNumber.Cmp(x.SerialNumber) == 0 { + return true + } + } + } + return false +} + +func (p *InclusionProofType) MarshalBinary() (data []byte, err error) { + if len(*p) > 256 { + return nil, fmt.Errorf("Inclusion proof is longer than the allowed size of 256 hashes") + } + var emptyOffset, i, l int + l = len(*p) + for ; i < l; i++ { + if !(len((*p)[i]) == 0 || len((*p)[i]) == 32) { + return nil, fmt.Errorf("Inclusion proof contains wrong sized hash (%d)", len((*p)[i])) + } + if len((*p)[i]) > 0 { + if emptyOffset != i { + // i-emptyOffset must be smaller than 256 since emptyOffset >= 0 and i < 256 + data = append(data, byte(i-emptyOffset)) + } + data = append(data, byte(0)) + data = append(data, (*p)[i]...) + emptyOffset = i + 1 + } + } + if emptyOffset != l { + if l-emptyOffset == 256 { + data = append(data, byte(0)) + } else { + data = append(data, byte(l-emptyOffset)) + } + } + return +} + +func (p *InclusionProofType) UnmarshalBinary(data []byte) (err error) { + var pNew InclusionProofType + if len(data) == 1 && data[0] == byte(0) { + // special case where the proof consists of 256 empty hashes + for i := 0; i < 256; i++ { + pNew = append(pNew, []byte{}) + } + } else { + // normal case where the number of consecutive empty hashes is always < 256 + var offset int + for offset < len(data) { + if data[offset] == 0 { + if offset+33 > len(data) { + return fmt.Errorf("Inclusion proof data is incomplete") + } + pNew = append(pNew, data[offset+1:offset+33]) + offset = offset + 33 + } else { + for i := 0; i < int(data[offset]); i++ { + pNew = append(pNew, []byte{}) + } + offset = offset + 1 + } + } + } + *p = append(*p, pNew...) + return +} + +func (p *proofType) MarshalBinary() ([]byte, error) { + data, err := p.marshalBinary() + if err != nil || !p.enableCompression { + return data, err + } + + var b bytes.Buffer + zw, err := flate.NewWriter(&b, flate.BestCompression) + if err != nil { + return nil, err + } + defer zw.Close() + + r := bytes.NewReader(data) + if _, err = io.Copy(zw, r); err != nil { + return nil, err + } + if err = zw.Flush(); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func (p *proofType) UnmarshalBinary(data []byte) error { + if p.enableCompression { + zr := flate.NewReader(bytes.NewReader(data)) + defer zr.Close() + var b bytes.Buffer + if _, err := io.Copy(bufio.NewWriter(&b), zr); err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { + return err + } + data = b.Bytes() + } + return p.unmarshalBinary(data) +} + +func (p *proofType) marshalBinary() (data []byte, err error) { + var d proofDataType + + for _, pme := range p.mapEntries { + me := *pme.toMapEntry() + meBytes, err := me.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("Couldn't marshal MapEntryType: %s", err) + } + d.MapEntries = append(d.MapEntries, meBytes) + } + + for _, ip := range p.inclusionProofs { + ipBytes, err := ip.MarshalBinary() + // ipBytes, err := asn1.Marshal(ip) + if err != nil { + return nil, fmt.Errorf("Couldn't marshal InclusionProofType: %s", err) + } + d.InclusionProofs = append(d.InclusionProofs, ipBytes) + } + + signedMapRoot, err := common.MarshalSignedMapRoot(&p.signedMapRoot) + if err != nil { + return nil, fmt.Errorf("Couldn't marshal trillian.SignedMapRoot: %s", err) + } + d.SignedMapRoot = signedMapRoot + + data, err = asn1.Marshal(d) + if err != nil { + return nil, fmt.Errorf("Couldn't marshal proofDataType: %s", err) + } + return data, nil +} + +func (p *proofType) unmarshalBinary(data []byte) error { + p.mapEntries = nil + p.inclusionProofs = nil + + var d proofDataType + _, err := asn1.Unmarshal(data, &d) + if err != nil { + return fmt.Errorf("Couldn't unmarshal proofDataType: %s", err) + } + + for _, meBytes := range d.MapEntries { + var me MapEntryType + err := me.UnmarshalBinary(meBytes) + if err != nil { + return fmt.Errorf("Couldn't unmarshal MapEntryType: %s", err) + } + + var pme proofMapEntryType + pme.fromMapEntry(&me) + p.mapEntries = append(p.mapEntries, pme) + } + + for _, ipBytes := range d.InclusionProofs { + var ip InclusionProofType + // _, err := asn1.Unmarshal(ipBytes, &ip) + err := ip.UnmarshalBinary(ipBytes) + if err != nil { + return fmt.Errorf("Couldn't unmarshal InclusionProofType: %s", err) + } + p.inclusionProofs = append(p.inclusionProofs, ip) + } + + err = common.UnmarshalSignedMapRoot(d.SignedMapRoot, &p.signedMapRoot) + if err != nil { + return fmt.Errorf("Couldn't unmarshal trillian.SignedMapRoot: %s", err) + } + + return nil +} + +func (p *InclusionProofType) ToString() string { + out := " 0 { + ctr += 1 + } + } + if p.exists(i) { + out += fmt.Sprintf("[%s: %d certs, %d wCerts, %d Rev, %d wRev, cSize=%d, pSize(%d)=%d]", suffix, len(e.Certificates), len(e.WildcardCertificates), len(e.Revocations), len(e.WildcardRevocations), certSize, ctr, len(data)) + } else { + out += fmt.Sprintf("[%s: EMPTY, pSize=%d]", suffix, ctr) + } + } + return out + ">" +} + +func (pme *proofMapEntryType) fromMapEntry(me *MapEntryType) { + pme.Certificates = make([][]x509.Certificate, len(me.Certificates)) + pme.Revocations = make([]RevocationMessageType, len(me.Revocations)) + pme.WildcardCertificates = make([][]x509.Certificate, len(me.WildcardCertificates)) + pme.WildcardRevocations = make([]RevocationMessageType, len(me.WildcardRevocations)) + pme.SubtreeRoot = make([]byte, len(me.SubtreeRoot)) + + copy(pme.Certificates, me.Certificates) + copy(pme.Revocations, me.Revocations) + copy(pme.WildcardCertificates, me.WildcardCertificates) + copy(pme.WildcardRevocations, me.WildcardRevocations) + copy(pme.SubtreeRoot, me.SubtreeRoot) +} + +func (pme *proofMapEntryType) toMapEntry() *MapEntryType { + var me MapEntryType + me.Certificates = make([][]x509.Certificate, len(pme.Certificates)) + me.Revocations = make([]RevocationMessageType, len(pme.Revocations)) + me.WildcardCertificates = make([][]x509.Certificate, len(pme.WildcardCertificates)) + me.WildcardRevocations = make([]RevocationMessageType, len(pme.WildcardRevocations)) + me.SubtreeRoot = make([]byte, len(pme.SubtreeRoot)) + + copy(me.Certificates, pme.Certificates) + copy(me.Revocations, pme.Revocations) + copy(me.WildcardCertificates, pme.WildcardCertificates) + copy(me.WildcardRevocations, pme.WildcardRevocations) + copy(me.SubtreeRoot, pme.SubtreeRoot) + return &me +} + +func (p *proofType) exists(level int) bool { + if level < 0 || level >= len(p.mapEntries) { + return false + } + e := p.mapEntries[level] + if len(e.GetCertificates()) > 0 { + return true + } + if len(e.GetWildcardCertificates()) > 0 { + return true + } + if len(e.GetRevocations()) > 0 { + return true + } + if len(e.GetWildcardRevocations()) > 0 { + return true + } + if len(e.GetSubtreeRoot()) > 0 { + return true + } + return false +} diff --git a/offlineauth/cyrill-k/trustflex/trillian/tclient/proof_test.go b/offlineauth/cyrill-k/trustflex/trillian/tclient/proof_test.go new file mode 100644 index 00000000..f239ed9f --- /dev/null +++ b/offlineauth/cyrill-k/trustflex/trillian/tclient/proof_test.go @@ -0,0 +1,168 @@ +// A Proof stores a set of map entries and corresponding inclusion proofs for the effective second level domain and all subdomains and a signed map root to verify the validity of the inclusion proofs + +package tclient + +import ( + "bufio" + "bytes" + "compress/flate" + "crypto/x509" + "github.com/google/trillian" + "io" + "log" + "math/big" + "testing" +) + +func TestProofTypeMarshalCompressed(t *testing.T) { + in := testCreateProof() + in.SetEnableCompression(true) + // log.Printf("in = %+v", in) + inEncoded, err := in.MarshalBinary() + if err != nil { + t.Errorf("Couldn't marshal proofType: %s", err) + } + var out proofType + out.SetEnableCompression(true) + err = out.UnmarshalBinary(inEncoded) + if err != nil { + t.Errorf("Couldn't unmarshal proofType: %s", err) + } + if !testProofTypeIsEqual(in, out) { + t.Errorf("proofType changed after marshal/unmarshal: %+v != %+v: %s", in.ToString(), out.ToString(), err) + } +} + +func TestProofTypeMarshal(t *testing.T) { + in := testCreateProof() + // log.Printf("in = %+v", in) + inEncoded, err := in.MarshalBinary() + if err != nil { + t.Errorf("Couldn't marshal proofType: %s", err) + } + var out proofType + err = out.UnmarshalBinary(inEncoded) + if err != nil { + t.Errorf("Couldn't unmarshal proofType: %s", err) + } + if !testProofTypeIsEqual(in, out) { + t.Errorf("proofType changed after marshal/unmarshal: %+v != %+v: %s", in.ToString(), out.ToString(), err) + } +} + +func testCreateProof() proofType { + var s1, s2, s3 big.Int + s1.SetUint64(1234) + s2.SetUint64(4321) + s3.SetUint64(6789) + var e1, e2 proofMapEntryType + e1.Certificates = [][]x509.Certificate{[]x509.Certificate{*testCreateCertificate(), *testCreateCertificate()}, []x509.Certificate{*testCreateCertificate(), *testCreateCertificate()}} + e1.Revocations = []RevocationMessageType{RevocationMessageType{SerialNumber: s1, Message: []byte{1, 2, 3, 4, 5, 6, 7, 8}}} + e1.WildcardCertificates = [][]x509.Certificate{} + e1.WildcardRevocations = []RevocationMessageType{} + e1.SubtreeRoot = []byte{3, 3, 3, 3, 3, 3, 3, 3} + e1.mapID = 3 + e2.Certificates = [][]x509.Certificate{[]x509.Certificate{*testCreateCertificate(), *testCreateCertificate(), *testCreateCertificate()}, []x509.Certificate{*testCreateCertificate(), *testCreateCertificate(), *testCreateCertificate()}, []x509.Certificate{*testCreateCertificate(), *testCreateCertificate(), *testCreateCertificate()}} + e2.Revocations = []RevocationMessageType{RevocationMessageType{SerialNumber: s2, Message: []byte{1, 2, 3, 4, 5, 6, 7, 8}}} + e2.WildcardCertificates = [][]x509.Certificate{} + e2.WildcardRevocations = []RevocationMessageType{RevocationMessageType{SerialNumber: s3, Message: []byte{6, 6, 6, 6, 6, 6, 6}}} + e2.SubtreeRoot = []byte{7, 7, 7, 7, 7, 7, 7, 7} + e2.mapID = 7 + + var p proofType + p.mapEntries = append(p.mapEntries, e1) + p.mapEntries = append(p.mapEntries, e2) + p.inclusionProofs = append(p.inclusionProofs, InclusionProofType{[]byte{1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}, []byte{}, []byte{}, []byte{5, 6, 7, 8, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}}) + p.inclusionProofs = append(p.inclusionProofs, InclusionProofType{[]byte{11, 22, 33, 44, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}, []byte{}, []byte{}, []byte{55, 66, 77, 88, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}}) + var smr trillian.SignedMapRoot + smr.MapRoot = []byte{1, 2, 3, 4, 5, 6, 7} + smr.Signature = []byte{9, 9, 9, 9, 9} + p.signedMapRoot = smr + p.SetDomain("a.b.com") + return p +} + +func testProofTypeIsEqual(a, b proofType) bool { + if len(a.mapEntries) != len(b.mapEntries) { + return false + } + if len(a.inclusionProofs) != len(b.inclusionProofs) { + return false + } + for i, ai := range a.mapEntries { + if !testProofMapEntryTypeIsEqual(ai, b.mapEntries[i]) { + return false + } + } + for i, ai := range a.inclusionProofs { + bi := b.inclusionProofs[i] + if len(ai) != len(bi) { + return false + } + for j, aij := range ai { + if bytes.Compare(aij, bi[j]) != 0 { + return false + } + } + } + if bytes.Compare(a.signedMapRoot.MapRoot, b.signedMapRoot.MapRoot) != 0 { + return false + } + if bytes.Compare(a.signedMapRoot.Signature, b.signedMapRoot.Signature) != 0 { + return false + } + return true +} + +func testProofMapEntryTypeIsEqual(a, b proofMapEntryType) bool { + if len(a.Certificates) != len(b.Certificates) { + return false + } + if len(a.WildcardCertificates) != len(b.WildcardCertificates) { + return false + } + if len(a.Revocations) != len(b.Revocations) { + return false + } + if len(a.WildcardRevocations) != len(b.WildcardRevocations) { + return false + } + if len(a.SubtreeRoot) != len(b.SubtreeRoot) { + return false + } + + for i, _ := range a.Certificates { + if len(a.Certificates[i]) != len(b.Certificates[i]) { + return false + } + for j, _ := range a.Certificates[i] { + if (a.Certificates[i][j].SerialNumber).Cmp(b.Certificates[i][j].SerialNumber) != 0 { + return false + } + } + } + for i, _ := range a.WildcardCertificates { + if len(a.WildcardCertificates[i]) != len(b.WildcardCertificates[i]) { + return false + } + for j, _ := range a.WildcardCertificates[i] { + if (a.WildcardCertificates[i][j].SerialNumber).Cmp(b.WildcardCertificates[i][j].SerialNumber) != 0 { + return false + } + } + } + for i, ai := range a.Revocations { + if (&ai.SerialNumber).Cmp(&b.Revocations[i].SerialNumber) != 0 { + return false + } + } + for i, ai := range a.WildcardRevocations { + if (&ai.SerialNumber).Cmp(&b.WildcardRevocations[i].SerialNumber) != 0 { + return false + } + } + if !bytes.Equal(a.SubtreeRoot, b.SubtreeRoot) { + return false + } + return true +} diff --git a/offlineauth/go.mod b/offlineauth/go.mod new file mode 100644 index 00000000..df7d3310 --- /dev/null +++ b/offlineauth/go.mod @@ -0,0 +1,39 @@ +module github.com/robinburkhard/rainsdeleg + +go 1.16 + +replace github.com/google/trillian => /home/burki/go/src/github.com/cyrill-k/trillian + +replace github.com/miekg/dns => /home/burki/go/src/github.com/robinburkhard/dns + +require ( + bou.ke/monkey v1.0.1 // indirect + github.com/coreos/bbolt v1.3.3 // indirect + github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a // indirect + github.com/cyrill-k/dns v1.0.13 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d // indirect + github.com/golangci/golangci-lint v1.17.2-0.20190910081718-bad04bb7378f // indirect + github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039 // indirect + github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6 // indirect + github.com/google/monologue v0.0.0-20190606152607-4b11a32b5934 // indirect + github.com/google/trillian v1.4.0 // indirect + github.com/google/trillian-examples v0.0.0-20190603134952-4e75ba15216c // indirect + github.com/gostaticanalysis/analysisutil v0.0.0-20190329151158-56bca42c7635 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect + github.com/letsencrypt/pkcs11key v2.0.1-0.20170608213348-396559074696+incompatible // indirect + github.com/letsencrypt/pkcs11key/v3 v3.0.0 // indirect + github.com/mattn/go-sqlite3 v1.10.0 // indirect + github.com/miekg/dns v1.0.14 // indirect + github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d // indirect + github.com/pelletier/go-toml v1.4.0 // indirect + github.com/shurcooL/go v0.0.0-20190330031554-6713ea532688 // indirect + github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect + google.golang.org/grpc v1.41.0 // indirect + mvdan.cc/unparam v0.0.0-20190310220240-1b9ccfa71afe // indirect + sourcegraph.com/sqs/pbtypes v1.0.0 // indirect +) diff --git a/offlineauth/go.sum b/offlineauth/go.sum new file mode 100644 index 00000000..5175507e --- /dev/null +++ b/offlineauth/go.sum @@ -0,0 +1,1508 @@ +bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= +bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.48.0/go.mod h1:gGOnoa/XMQYHAscREBlbdHduGchEaP9N0//OXdrPI/M= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.93.3 h1:wPBktZFzYBcCZVARvwVKqH1uEj+aLXofJEtrb4oOsio= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/spanner v1.1.0/go.mod h1:TzTaF9l2ZY2CIetNvVpUu6ZQy8YEOtzB6ICa5EwYjL0= +cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs= +cloud.google.com/go/spanner v1.18.0/go.mod h1:LvAjUXPeJRGNuGpikMULjhLj/t9cRvdc+fxRoLiugXA= +cloud.google.com/go/spanner v1.25.0/go.mod h1:kQUft3x355hzzaeFbObjsvkzZDgpDkesp3v75WBnI8w= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= +code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= +contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= +contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= +contrib.go.opencensus.io/exporter/stackdriver v0.13.0/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c= +contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ= +contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= +github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= +github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= +github.com/apache/beam v2.32.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ= +github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= +github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= +github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158 h1:CevA8fI91PAnP8vpnXuB8ZYAZ5wqY86nAbxfgK8tWO4= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyrill-k/dns v1.0.13 h1:Bm2VjQl1DYMyUC/AZSp/jhJBob4MGY0uejr7Gr1c1kM= +github.com/cyrill-k/dns v1.0.13/go.mod h1:K9KO48YzzYE1Xa7OH/LKcSWGe7t68XsS5K22let+zqY= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/emicklei/proto v1.6.12/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.6.13/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.7.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.8.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 h1:fP+fF0up6oPY49OrjPrhIJ8yQfdIM85NXMLkMg1EXVs= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.3.0-java h1:bV5JGEB1ouEzZa0hgVDFFiClrUEuGWRaAc/3mxR2QK0= +github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= +github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fullstorydev/grpcurl v1.3.2/go.mod h1:kvk8xPCXOrwVd9zYdjy+xSOT4YWm6kyth4Y9NMfBns4= +github.com/fullstorydev/grpcurl v1.4.0/go.mod h1:kvk8xPCXOrwVd9zYdjy+xSOT4YWm6kyth4Y9NMfBns4= +github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= +github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= +github.com/fullstorydev/grpcurl v1.8.2 h1:2II5e++aFnctnPJir3GL6cPSwF69Ord1u/9O+fv1vrI= +github.com/fullstorydev/grpcurl v1.8.2/go.mod h1:YvWNT3xRp2KIRuvCphFodG0fKkMXwaxA9CJgKCcyzUQ= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobuffalo/flect v0.1.6/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.17.2-0.20190910081718-bad04bb7378f/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg= +github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/certificate-transparency-go v1.1.0/go.mod h1:i+Q7XY+ArBveOUT36jiHGfuSK1fHICIg6sUkRxPAbCs= +github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ= +github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6 h1:8oLg/gKOoZGs9x96bSIsoFsTMFqWEekNOp4fbSpdcgs= +github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= +github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= +github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/monologue v0.0.0-20190606152607-4b11a32b5934/go.mod h1:6NTfaQoUpg5QmPsCUWLR3ig33FHrKXhTtWzF0DVdmuk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ= +github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa h1:lBiua/s4sEzsFPJGAwwROS4/w+jCQfw4lc3yLh7yMKM= +github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa/go.mod h1:s4jO3Ai4NSvxucdvqUHON0bCqJyoya32eNw6XJwsmNc= +github.com/google/trillian v1.4.0 h1:Wa7XHCVzl8RLsUOr2SzoHUZHYjv0G8KMO1xZGamYkbA= +github.com/google/trillian v1.4.0/go.mod h1:1Bja2nEgMDlEJWWRXBUemSPG9qYw84ZYX2gHRVHlR+g= +github.com/google/trillian-examples v0.0.0-20190603134952-4e75ba15216c/go.mod h1:WgL3XZ3pA8/9cm7yxqWrZE6iZkESB2ItGxy5Fo6k2lk= +github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ= +github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190329151158-56bca42c7635/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4oWPMvH1+v+DLYlMCecgumhhgnxAPdqDIFHI= +github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.5.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= +github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= +github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/letsencrypt/pkcs11key v2.0.1-0.20170608213348-396559074696+incompatible/go.mod h1:iGYXKqDXt0cpBthCHdr9ZdsQwyGlYFh/+8xa4WzIQ34= +github.com/letsencrypt/pkcs11key/v3 v3.0.0/go.mod h1:sfoiYd3g5fIel4ZANw27sbgXzN43FY5hNP6uxEUywkM= +github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/lyft/protoc-gen-validate v0.0.14/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/lyft/protoc-gen-validate v0.1.0/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/pseudomuto/protoc-gen-doc v1.3.0/go.mod h1:fwtQAY9erXp3mC92O8OTECnDlJT2r0Ff4KSEKbGEmy0= +github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= +github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.1/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go v0.0.0-20190330031554-6713ea532688/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= +github.com/uber/prototool v1.8.2-0.20190910022025-7df3b957ffe3/go.mod h1:fQyN8ZUYd9QoSiV0T/Da6NUSZY4ARW+EfJaL/4V1DD8= +github.com/uber/prototool v1.9.0/go.mod h1:srCJMbeTuTT/1xkYIuUc1iCKsjjn8RBw9xxQl0R4aZg= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= +github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.etcd.io/etcd v3.3.18+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= +go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU= +go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8= +go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo= +go.etcd.io/etcd/etcdctl/v3 v3.5.0 h1:i8DGjR9gBRoS6NEHF3XBxxh7QwL1DyilXMCkHpyy6zM= +go.etcd.io/etcd/etcdctl/v3 v3.5.0/go.mod h1:vGTfKdsh87RI7kA2JHFBEGxjQEYx+pi299wqEOdi34M= +go.etcd.io/etcd/etcdutl/v3 v3.5.0 h1:orNfs85GWmiOl0p23Yi9YRfHNb3Qfdlt0wVFkPTRVxQ= +go.etcd.io/etcd/etcdutl/v3 v3.5.0/go.mod h1:o98rKMCibbFAG8QS9KmvlYDGDShmmIbmRE8vSofzYNg= +go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY= +go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w= +go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= +go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30= +go.etcd.io/etcd/tests/v3 v3.5.0 h1:+uMuHYKKlLUzbW322XrQXbaGM9qiV7vUL+AEPT/KYY4= +go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE= +go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To= +go.etcd.io/etcd/v3 v3.5.0 h1:fs7tB+L/xRDi/+p9qKuaPGCtMX6vkovLRXTqvEE98Ek= +go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4= +go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= +golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a h1:4Kd8OPUx1xgUwrHDaviWZO8MsgoZTZYC3g+8m16RBww= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324 h1:pAwJxDByZctfPwzlNGrDN2BQLsdPb9NkhoTJtUkAO28= +golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190213192042-740235f6c0d8/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191105231337-689d0f08e67a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= +google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190605220351-eb0b1bdb6ae6/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115221424-83cc0476cb11/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab h1:dkb90hr43A2Q5as5ZBphcOF2II0+EqfCBqGp7qFSpN4= +google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8 h1:XosVttQUxX8erNhEruTu053/VchgYuksoS9Bj/OITjU= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= +mvdan.cc/unparam v0.0.0-20190310220240-1b9ccfa71afe/go.mod h1:BnhuWBAqxH3+J5bDybdxgw5ZfS+DsVd4iylsKQePN8o= +pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= diff --git a/offlineauth/keyManager/keyManager.go b/offlineauth/keyManager/keyManager.go new file mode 100644 index 00000000..38c51c44 --- /dev/null +++ b/offlineauth/keyManager/keyManager.go @@ -0,0 +1,63 @@ +package keyManager + +import ( + "crypto" + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "github.com/robinburkhard/rainsdeleg/common" +) + +func CreateRSAKey(path string) error { + PrivateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return err + } + err = common.StoreRSAPrivateKeyPEM(PrivateKey, path) + if err != nil { + return err + } + return nil +} + +func CreateEd25519Key(path string) error { + _, privatekey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return err + } + err = common.StorePrivateKeyEd25519(path, privatekey) + if err != nil { + return err + } + return nil +} + + + +func CreateSelfSignedCACertificate(alg string, keyPath string, certPath string) error { + var privKey crypto.Signer + switch alg { + case "RSA": + var err error + privKey, err = common.LoadRSAPrivateKeyPEM(keyPath) + if err != nil { + return err + } + case "Ed25519": + var err error + privKey, err = common.LoadPrivateKeyEd25519(keyPath) + if err != nil { + return err + } + } + certbytes , err := common.CreateSelfSignedCertCA(privKey.Public(), privKey) + if err != nil { + return err + } + err = common.StoreCertificatePEM(certPath, certbytes) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/offlineauth/parent/parent.go b/offlineauth/parent/parent.go new file mode 100644 index 00000000..f60cb00e --- /dev/null +++ b/offlineauth/parent/parent.go @@ -0,0 +1,339 @@ +package parent + +import ( + "bytes" + "crypto" + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + logger15 "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/requests" + "io/ioutil" + "log" + "net/http" +) + +var logger = logger15.New("Module", "Parent") + +type Parent struct { + PublicKey interface{} + PrivateKey interface{} + AuthenticationType string + Certificate *x509.Certificate + keyType string + LogCheckerExtAddress string + CAAddress string + OutputDir string + +} + +func NewParent(config Config) *Parent { + if config.PrivateKeyAlgorithm == ""{ + return nil + } + if config.Zone == ""{ + return nil + } + var privKey interface{} + var pubkey interface{} + var cert *x509.Certificate + + if config.PrivateKeyPath == ""{ + switch config.PrivateKeyAlgorithm { + case "RSA": + privKey, _ = rsa.GenerateKey(rand.Reader, 2048) + pubkey = privKey.(*rsa.PrivateKey).Public() + case "Ed25519": + pubkey, privKey, _ = ed25519.GenerateKey(rand.Reader) + } + } else { + switch config.PrivateKeyAlgorithm{ + case "RSA": + var err error + privKey, err = common.LoadRSAPrivateKeyPEM(config.PrivateKeyPath) + if err != nil { + log.Fatal(err) + } + pubkey = privKey.(*rsa.PrivateKey).Public() + case "Ed25519": + var err error + privKey, err = common.LoadPrivateKeyEd25519(config.PrivateKeyPath) + if err != nil { + log.Fatal(err) + } + pubkey = privKey.(ed25519.PrivateKey).Public() + } + } + + if config.CertificatePath == "" && config.AuthenticationType == "certificate"{ + certbytes, _ := common.CreateSelfSignedCert(pubkey, interface{}(privKey), config.Zone) + cert, _ = x509.ParseCertificate(certbytes) + } else if config.AuthenticationType == "certificate" { + var err error + cert, err = common.LoadCertificatePEM(config.CertificatePath) + if err != nil { + log.Fatal(err) + } + } + + + par := Parent{ + PublicKey: pubkey, + PrivateKey: privKey, + AuthenticationType: config.AuthenticationType, + Certificate: cert, + keyType: config.PrivateKeyAlgorithm, + LogCheckerExtAddress: config.LogCheckerExtAddress, + CAAddress: config.CAAddress, + OutputDir: config.OutputDir, + + } + + return &par + +} + +func LoadConfig(Path string) (Config, error){ + conf := Config{} + file, err := ioutil.ReadFile(Path) + if err != nil { + return Config{}, err + } + if err = json.Unmarshal(file, &conf); err != nil { + return Config{}, err + } + + return conf, nil +} + +func (p *Parent) NewDlg(csrbytes []byte, IndSubZone bool) ([]byte, error){ + logger.Info("Parent: Creating NewDlg Request") + var IndSubZoneString string + if IndSubZone { + IndSubZoneString = "yes" + } else { + IndSubZoneString = "no" + } + payload := requests.NewDlgPayload{ + Req_type: "NewDlgReq", + IndependentSubZone: IndSubZoneString, + Csr: common.EncodeBase64(csrbytes), + } + + parentRequest, _ := p.BuildNewDlgRequest(payload) + + parentRequest.Signature = p.SignNewDlgRequest(parentRequest) + + resp, err := p.PostNewDlgRequest(parentRequest) + if err != nil { + return nil, err + } + + if resp.Cert == ""{ + return nil, errors.New("Error from CA: " + resp.Error) + } + + certbytes, _ := common.DecodeBase64(resp.Cert) + err = CheckCSRCertMatch(csrbytes, certbytes) + if err != nil { + return nil, err + } + + logger.Info("Parent: Creating Checker Extension Request") + checkerReq := p.BuildCheckNewDlgReq(certbytes) + checkerReq.Signature = p.SignCheckNewDlgRequest(checkerReq) + checkResp, err := p.PostCheckNewDlgReq(checkerReq) + if err != nil { + logger.Warn("Parent: Checker Request FAILED") + return nil, err + } + + if checkResp.Status != "OK" { + logger.Warn("Parent: Checker Error: " + checkResp.Error) + return nil, errors.New(checkResp.Error) + } + + logger.Info("Parent: Checker Request OK") + return certbytes, nil +} + +func CheckCSRCertMatch(csrbytes []byte, certbytes []byte) (error){ + csr, err := x509.ParseCertificateRequest(csrbytes) + if err != nil { + return err + } + cert, err := x509.ParseCertificate(certbytes) + if err != nil { + return err + } + + match := true + + switch csr.PublicKey.(type) { + case *rsa.PublicKey: + csrKey, _ := csr.PublicKey.(*rsa.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + match = false + } + case ed25519.PublicKey: + csrKey, _ := csr.PublicKey.(ed25519.PublicKey) + if !csrKey.Equal(cert.PublicKey){ + match = false + } + default: + match = false + } + for i , name := range csr.DNSNames { + if !(name == cert.DNSNames[i]) { + match = false + } + } + + if !match { + return errors.New("CA Signed Certificate and CSR do not match") + } + + return nil + +} + +func (p *Parent) BuildNewDlgRequest(payload requests.NewDlgPayload) (requests.NewDlgRequest, error) { + var parentCert string + if p.Certificate != nil { + parentCert = common.EncodeBase64(p.Certificate.Raw) + } else { + parentCert = "" + } + + //fmt.Println(reflect.TypeOf(p.PublicKey)) + parentPublicKey, _, err := common.EncodePublicKey(p.PublicKey) + if err != nil { + return requests.NewDlgRequest{}, err + } + + parentRequest := requests.NewDlgRequest{ + Header: &requests.ParentHeader{ + Parent_auth_type: p.AuthenticationType, + Parent_cert: parentCert, + Alg: p.keyType, + Pubkey: parentPublicKey, + }, + Payload: &payload, + Signature: "", + } + + return parentRequest, nil +} + +func (p *Parent) SignNewDlgRequest(req requests.NewDlgRequest) string { + headerSig, _ := json.Marshal(req.Header) + payloadSig, _ := json.Marshal(req.Payload) + sigbytes := []byte{} + + switch p.keyType { + case "Ed25519": + sigbytes = ed25519.Sign(p.PrivateKey.(ed25519.PrivateKey), append(headerSig, payloadSig...)) + case "RSA": + sha256 := sha256.New() + sha256.Write(append(headerSig, payloadSig...)) + hash := sha256.Sum(nil) + sigbytes, _ = rsa.SignPSS(rand.Reader, p.PrivateKey.(*rsa.PrivateKey), crypto.SHA256, hash, nil) + default: + return "" + } + + encodedSig := common.EncodeBase64(sigbytes) + return encodedSig +} + +func (p *Parent) PostNewDlgRequest(req requests.NewDlgRequest) (requests.CAResponse, error) { + jsonreq, _ := json.Marshal(req) + address := "http://" + p.CAAddress + "/NewDlg" // TODO change to https + + log.Printf("Posting Request: %#v\n", req) + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + return requests.CAResponse{}, err + } + defer resp.Body.Close() + + var caResp requests.CAResponse + err = json.NewDecoder(resp.Body).Decode(&caResp) + log.Printf("Response: %#v\n", caResp) + + if err != nil { + return requests.CAResponse{}, err + } + return caResp, nil +} + +func (p *Parent) BuildCheckNewDlgReq(cert []byte) requests.CheckNewDlgRequest { + var parentCert string + if p.Certificate != nil { + parentCert = common.EncodeBase64(p.Certificate.Raw) + } else { + parentCert = "" + } + parentPublicKey, _, _ := common.EncodePublicKey(p.PublicKey) + + req := requests.CheckNewDlgRequest{ + Header: &requests.ParentHeader{ + Parent_auth_type: p.AuthenticationType, + Parent_cert: parentCert, + Pubkey: parentPublicKey, + Alg: p.keyType, + }, + Payload: &requests.CheckNewDlgPayload{ + Cert: common.EncodeBase64(cert), + }, + Signature: "", + } + + return req +} + +func (p *Parent) SignCheckNewDlgRequest(req requests.CheckNewDlgRequest) string { + headerSig, _ := json.Marshal(req.Header) + payloadSig, _ := json.Marshal(req.Payload) + sigbytes := []byte{} + + switch p.keyType { + case "Ed25519": + sigbytes = ed25519.Sign(p.PrivateKey.(ed25519.PrivateKey), append(headerSig, payloadSig...)) + case "RSA": + sha256 := sha256.New() + sha256.Write(append(headerSig, payloadSig...)) + hash := sha256.Sum(nil) + sigbytes, _ = rsa.SignPSS(rand.Reader, p.PrivateKey.(*rsa.PrivateKey), crypto.SHA256, hash, nil) + default: + return "" + } + encodedSig := common.EncodeBase64(sigbytes) + return encodedSig +} + +func (p *Parent) PostCheckNewDlgReq(req requests.CheckNewDlgRequest) (requests.CheckResponse, error) { + jsonreq, _ := json.Marshal(req) + address := "http://" + p.LogCheckerExtAddress + "/CheckNewDlg" // TODO change to https + resp, err := http.Post(address, "application/json", bytes.NewReader(jsonreq)) + if err != nil { + fmt.Println(err) + } + defer resp.Body.Close() + + var checkResp requests.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&checkResp) + log.Printf("Response: %#v\n", checkResp) + + if err != nil { + return requests.CheckResponse{}, err + } + return checkResp, nil + +} \ No newline at end of file diff --git a/offlineauth/parent/parentconfig.go b/offlineauth/parent/parentconfig.go new file mode 100644 index 00000000..822e6e73 --- /dev/null +++ b/offlineauth/parent/parentconfig.go @@ -0,0 +1,12 @@ +package parent + +type Config struct { + Zone string + AuthenticationType string + LogCheckerExtAddress string + PrivateKeyAlgorithm string + PrivateKeyPath string + CertificatePath string + CAAddress string + OutputDir string +} \ No newline at end of file diff --git a/offlineauth/requests/README.md b/offlineauth/requests/README.md new file mode 100644 index 00000000..ac1e7e89 --- /dev/null +++ b/offlineauth/requests/README.md @@ -0,0 +1,38 @@ +## NewDlg Request + +json object containing keys: +- *header* +- *payload* +- *signature* + +``` +{ + "header": + { + "parent_auth_type": "certificate" / "dnssec", + "parent_cert": urlsafe_base64(bytes(Certificate)), + "alg": "Ed25519" / "RSA", + "pubkey": urlsafe_base64(bytes(PublicKey)) + }, + "payload": + { + "req_type":"NewDlgReq", + "csr": urlsafe_base64(bytes(CertificateSigningRequest)), + }, + "signature": urlsafe_base64(bytes(Signature)) +} + +``` + +**Signature**: base64 encoded signature. Message to sign is ***bytes(json(header))||bytes(json(payload))***, signed with the secret key for public key in certificate in header +**pubkey**: encoding RSA: PKCS1 Public Key, encoding Ed25519: PKIX Public Key + + +### CaResponse: +``` +{ + "cert": urlsafebase64(bytes(certificate)), + "error": string +} +``` + diff --git a/offlineauth/requests/errormsg.go b/offlineauth/requests/errormsg.go new file mode 100644 index 00000000..1260200a --- /dev/null +++ b/offlineauth/requests/errormsg.go @@ -0,0 +1,54 @@ +package requests + + +const ( + CsrDecodeError = iota + CertDecodeError + CsrParseError + CertParseError + CsrSignatureInvalid + CsrSANDNSMissing + ParentAuthDNSSECFailed + ParentAuthCertDecodeError + ParentAuthCertParseError + ParentAuthCertInvalid + MapServerConnectionFailed + AuthTypeMissing + InvalidSignature + ConflictingCertInLog + CertIssueError + RequiredCertNotInLog + OldKeyDecodeError + JSONDecodeError + ParentCertificateMissing + CSRMissing + UnsupportedAlg + CertInvalid + +) + +var ErrorMsg = map[int]string { + CsrDecodeError: "Csr Decode Error", + CertDecodeError: "Cert Decode Error", + CsrParseError: "Csr Parse Error", + CertParseError: "Cert Parse Error", + CsrSignatureInvalid: "Csr Signature Invalid", + CsrSANDNSMissing: "Csr SAN DNS Missing", + ParentAuthDNSSECFailed: "Parent Auth DNSSEC Failed", + ParentAuthCertDecodeError: "Parent Auth Cert Decode Error", + ParentAuthCertParseError: "Parent Auth Cert Parse Error", + ParentAuthCertInvalid: "Parent Auth Cert Invalid", + MapServerConnectionFailed: "Map Server Connection Failed", + AuthTypeMissing: "Auth Type Missing", + InvalidSignature: "Invalid Signature", + ConflictingCertInLog: "Conflicting Cert In Log", + CertIssueError: "Cert Issue Error", + RequiredCertNotInLog: "Required Cert Not In Log", + OldKeyDecodeError: "Old Key Decode Error", + JSONDecodeError: "JSON Decode Error", + ParentCertificateMissing: "Parent Certificate Missing", + CSRMissing: "CSR Missing", + UnsupportedAlg: "Unsupported Alg", + CertInvalid: "Certificate Invalid", + +} diff --git a/offlineauth/requests/requests.go b/offlineauth/requests/requests.go new file mode 100644 index 00000000..c1b72112 --- /dev/null +++ b/offlineauth/requests/requests.go @@ -0,0 +1,68 @@ +package requests + +type NewDlgRequest struct { + Header *ParentHeader `json:"header"` + Payload *NewDlgPayload `json:"payload"` + Signature string `json:"signature"` +} + +type NewDlgPayload struct { + Req_type string `json:"req_type"` + IndependentSubZone string `json:"ind_sub_zone"` + Csr string `json:"csr"` +} + +type ParentHeader struct { + Parent_auth_type string `json:"parent_auth_type"` + Parent_cert string `json:"parent_cert,omitempty"` + Alg string `json:"alg"` + Pubkey string `json:"pubkey"` +} + +type CAResponse struct { + Cert string `json:"cert, omitempty"` + Error string `json:"error, omitempty"` +} + +type CheckNewDlgRequest struct { + Header *ParentHeader + Payload *CheckNewDlgPayload `json:"payload"` + Signature string `json:"signature"` +} +type CheckNewDlgPayload struct { + Cert string `json:"cert"` +} + +type CheckResponse struct { + Status string `json:"status"` + Error string `json:"error"` +} + +type ReNewDlgRequest struct { + Csr string `json:"csr"` +} + +type CheckReNewDlgRequest struct { + Cert string `json:"cert"` + Signature string `json:"signature"` +} + +type KeyChangeDlgRequest struct { + Csr string `json:"csr"` + OldKeyAlg string `json:"old_key_alg"` + OldKey string `json:"old_key"` + Signature string `json:"signature"` +} + +type CheckKeyChangeDlgRequest struct { + Cert string `json:"cert"` + OldKeyAlg string `json:"old_key_alg"` + OldKey string `json:"old_key"` + Signature string `json:"signature"` +} + +type RevokeDlgRequest struct { + Cert string `json:"cert"` + Signature string `json:"signature"` +} + diff --git a/offlineauth/test/demo/ca.cert b/offlineauth/test/demo/ca.cert new file mode 100644 index 00000000..aa5ef35d --- /dev/null +++ b/offlineauth/test/demo/ca.cert @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBJjCB2aADAgECAgEBMAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDQwNzEzMjQ1NFoXDTIzMDMyOTEzMjQ1NFowGzEZMBcGA1UEAxMQ +UkhJTkUgRVhBTVBMRSBDQTAqMAUGAytlcAMhAC5C5QWux20nmQIqmYZcvPAoV9vP +gKCy7DeAPrCZ7Cpso0IwQDAOBgNVHQ8BAf8EBAMCAoQwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUJkWeKMencxgUuV4Z/LJEOLObgW8wBQYDK2VwA0EAgbZjKA+x +Y9WbE3KlmLCArDzXOxV288li/HYgx00kVvIJXDOtuI+ujTmMxSL6/qQIm2/3QkeF +4ZBiHAo+qb00AQ== +-----END CERTIFICATE----- diff --git a/offlineauth/test/demo/ca.conf b/offlineauth/test/demo/ca.conf new file mode 100644 index 00000000..99ffd16b --- /dev/null +++ b/offlineauth/test/demo/ca.conf @@ -0,0 +1,10 @@ +{ + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "demo/ca.key", + "CertificatePath": "demo/ca.cert", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "testdata/mappk1.pem", + "MapId": 2727696932843049039, + "ServerAddress": "localhost:10000", + "RootCertsPath": "demo/roots/" +} \ No newline at end of file diff --git a/offlineauth/test/demo/ca.key b/offlineauth/test/demo/ca.key new file mode 100644 index 00000000..a9534734 --- /dev/null +++ b/offlineauth/test/demo/ca.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +iTW+/VlUuS7aDUaGCRNGBDB+M+SMCQOwOChWSRSdZcUuQuUFrsdtJ5kCKpmGXLzw +KFfbz4Cgsuw3gD6wmewqbA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/demo/ch.cert b/offlineauth/test/demo/ch.cert new file mode 100644 index 00000000..9d7f89ca --- /dev/null +++ b/offlineauth/test/demo/ch.cert @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBRzCB+qADAgECAgF7MAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDQwNzEzMjQ1NloXDTIzMDMyOTEzMjQ1NlowGTEXMBUGA1UEAxMO +UkhJTkU6Y2gucmFpbnMwKjAFBgMrZXADIQARt1bFS6qUvvhdq8LctEwOXqnGQAjz +PzjQ+WuNlnPwhKNlMGMwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHwYD +VR0jBBgwFoAUJkWeKMencxgUuV4Z/LJEOLObgW8wEwYDVR0RBAwwCoIIY2gucmFp +bnMwDQYEK4N0CQQFMAMBAf8wBQYDK2VwA0EANtrQwRJXBR8yfRr1zk/qdNry/5/8 +AedyqZrfjrf4xi6+tyj9URsl+DGEP64rs0Rr4SXjuv9wTAr30l8D0LlcAA== +-----END CERTIFICATE----- diff --git a/offlineauth/test/demo/ch.conf b/offlineauth/test/demo/ch.conf new file mode 100644 index 00000000..769a8f12 --- /dev/null +++ b/offlineauth/test/demo/ch.conf @@ -0,0 +1,10 @@ +{ + "Zone": "ch.rains", + "AuthenticationType": "certificate", + "LogCheckerExtAddress": "localhost:10001", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "demo/ch.key", + "CertificatePath": "demo/ch.cert", + "CAAddress": "localhost:10000", + "OutputDir": "demo/" +} \ No newline at end of file diff --git a/offlineauth/test/demo/ch.key b/offlineauth/test/demo/ch.key new file mode 100644 index 00000000..5b019a11 --- /dev/null +++ b/offlineauth/test/demo/ch.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +B9rG0wgQuJdBNnNjuXgRYqAUSp3H3NsMNDfUM26g72ERt1bFS6qUvvhdq8LctEwO +XqnGQAjzPzjQ+WuNlnPwhA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/demo/chdemo.cert b/offlineauth/test/demo/chdemo.cert new file mode 100644 index 00000000..0f1e8bd8 --- /dev/null +++ b/offlineauth/test/demo/chdemo.cert @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBUDCCAQKgAwIBAgIBezAFBgMrZXAwGzEZMBcGA1UEAxMQUkhJTkUgRVhBTVBM +RSBDQTAeFw0yMjA0MDcxMzI0MzBaFw0yMzAzMjkxMzI0MzBaMB0xGzAZBgNVBAMT +ElJISU5FOmNoZGVtby5yYWluczAqMAUGAytlcAMhANVYWU9FfsA21siTojKyhi5Z +O5d3prdUgfH8II+i5rVso2kwZzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIw +ADAfBgNVHSMEGDAWgBTnzIex9pPMUB1OfxJdWZRBqsYtdDAXBgNVHREEEDAOggxj +aGRlbW8ucmFpbnMwDQYEK4N0CQQFMAMBAf8wBQYDK2VwA0EAMhRLO9wVTEkR4dpP +Uqj69BeiFYg36mZzl3ka9D9KVJcvWdNZPCkEdn7wYOfhm7x+gkLMom5NNjXu+1+i +1YdHAw== +-----END CERTIFICATE----- diff --git a/offlineauth/test/demo/chdemo.conf b/offlineauth/test/demo/chdemo.conf new file mode 100644 index 00000000..a8c3b788 --- /dev/null +++ b/offlineauth/test/demo/chdemo.conf @@ -0,0 +1,10 @@ +{ + "Zone": "chdemo.rains", + "AuthenticationType": "certificate", + "LogCheckerExtAddress": "localhost:10001", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "demo/chdemo.key", + "CertificatePath": "demo/chdemo.cert", + "CAAddress": "localhost:10000", + "OutputDir": "demo/" +} \ No newline at end of file diff --git a/offlineauth/test/demo/chdemo.key b/offlineauth/test/demo/chdemo.key new file mode 100644 index 00000000..788bb086 --- /dev/null +++ b/offlineauth/test/demo/chdemo.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +nRlDva8VA+BJzhr5DjVGCwlzYNrhtrqx9wnJZI7Ea0TVWFlPRX7ANtbIk6IysoYu +WTuXd6a3VIHx/CCPoua1bA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/demo/checker.conf b/offlineauth/test/demo/checker.conf new file mode 100644 index 00000000..dd371a6b --- /dev/null +++ b/offlineauth/test/demo/checker.conf @@ -0,0 +1,10 @@ +{ + "LogID": 2110187651566808891, + "LogAddress": "172.18.0.3:8090", + "LogPkeyPath": "testdata/logpk1.pem", + "MapID": 2727696932843049039, + "MapAddress": "172.18.0.5:8094", + "MapPkeyPath": "testdata/mappk1.pem", + "RootCertsPath": "demo/roots/", + "ServerAddress": "localhost:10001" +} \ No newline at end of file diff --git a/offlineauth/test/demo/debugcsr.csr b/offlineauth/test/demo/debugcsr.csr new file mode 100644 index 00000000..0ba569eb --- /dev/null +++ b/offlineauth/test/demo/debugcsr.csr @@ -0,0 +1,7 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIG+MHICAQAwGTEXMBUGA1UEAxMOUkhJTkU6Y2gucmFpbnMwKjAFBgMrZXADIQAR +t1bFS6qUvvhdq8LctEwOXqnGQAjzPzjQ+WuNlnPwhKAmMCQGCSqGSIb3DQEJDjEX +MBUwEwYDVR0RBAwwCoIIY2gucmFpbnMwBQYDK2VwA0EAXbwfCkCEvcMx6O4m3tdn +coMS2lZm8SBQtMNTxhMO43iLc4hW+PmEE9wdBPl4N2kUxD2TKusDBO8qnn+NjXiK +Cg== +-----END CERTIFICATE REQUEST----- diff --git a/offlineauth/test/demo/ethz.ch.rains.key b/offlineauth/test/demo/ethz.ch.rains.key new file mode 100644 index 00000000..db66619a --- /dev/null +++ b/offlineauth/test/demo/ethz.ch.rains.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +VXtu0Od8f6Eweot2RzHXqGy9WuNF76pMzfYpxb+dlkHHyKntCiGb2BfP+QWgIEG1 +9fx5Bu/nPMYdk3RI2PLiwA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/demo/ethz.ch.rains_Cert.pem b/offlineauth/test/demo/ethz.ch.rains_Cert.pem new file mode 100644 index 00000000..3c4d7e59 --- /dev/null +++ b/offlineauth/test/demo/ethz.ch.rains_Cert.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBUjCCAQSgAwIBAgIBezAFBgMrZXAwGzEZMBcGA1UEAxMQUkhJTkUgRVhBTVBM +RSBDQTAeFw0yMjA0MDcxMzQ4MzBaFw0yMzAzMjkxMzQ4MzBaMB4xHDAaBgNVBAMT +E1JISU5FOmV0aHouY2gucmFpbnMwKjAFBgMrZXADIQDHyKntCiGb2BfP+QWgIEG1 +9fx5Bu/nPMYdk3RI2PLiwKNqMGgwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQC +MAAwHwYDVR0jBBgwFoAUJkWeKMencxgUuV4Z/LJEOLObgW8wGAYDVR0RBBEwD4IN +ZXRoei5jaC5yYWluczANBgQrg3QJBAUwAwEB/zAFBgMrZXADQQC+YRHtnk6ts6d4 +KPrY4BiJT9YPvN/Sg5UExC4hzPAzBar8YIOCHM9uD995vEPLY1jR4EihFOBuv+qG +Cug9vkYL +-----END CERTIFICATE----- diff --git a/offlineauth/test/demo/ethz.ch.rains_Csr.pem b/offlineauth/test/demo/ethz.ch.rains_Csr.pem new file mode 100644 index 00000000..f0b231b6 --- /dev/null +++ b/offlineauth/test/demo/ethz.ch.rains_Csr.pem @@ -0,0 +1,7 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIHIMHwCAQAwHjEcMBoGA1UEAxMTUkhJTkU6ZXRoei5jaC5yYWluczAqMAUGAytl +cAMhAMfIqe0KIZvYF8/5BaAgQbX1/HkG7+c8xh2TdEjY8uLAoCswKQYJKoZIhvcN +AQkOMRwwGjAYBgNVHREEETAPgg1ldGh6LmNoLnJhaW5zMAUGAytlcANBALavCqS6 +ZwOBXeeB2ycApWfG6zyCRPPr00r4aBVy9uLWqwda5JTvO4bYR9b/TsMQHEwa6M8r +1XgJmuxf87CIwQk= +-----END CERTIFICATE REQUEST----- diff --git a/offlineauth/test/demo/root.conf b/offlineauth/test/demo/root.conf new file mode 100644 index 00000000..95ceb7e2 --- /dev/null +++ b/offlineauth/test/demo/root.conf @@ -0,0 +1,10 @@ +{ + "Zone": "rains", + "AuthenticationType": "NOAUTH", + "LogCheckerExtAddress": "localhost:10001", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "demo/root.key", + "CertificatePath": "", + "CAAddress": "localhost:10000", + "OutputDir": "demo/" +} \ No newline at end of file diff --git a/offlineauth/test/demo/root.key b/offlineauth/test/demo/root.key new file mode 100644 index 00000000..e0d53a18 --- /dev/null +++ b/offlineauth/test/demo/root.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +sB0tprbzJ6uVsm0o5TpgIaaZukxdmCmrWupRat8gtHDR7mweti27BBmFr9Wt5rP2 +te16N+TVp1qNl//xcbO4IA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/demo/roots/ca.cert b/offlineauth/test/demo/roots/ca.cert new file mode 100644 index 00000000..aa5ef35d --- /dev/null +++ b/offlineauth/test/demo/roots/ca.cert @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBJjCB2aADAgECAgEBMAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDQwNzEzMjQ1NFoXDTIzMDMyOTEzMjQ1NFowGzEZMBcGA1UEAxMQ +UkhJTkUgRVhBTVBMRSBDQTAqMAUGAytlcAMhAC5C5QWux20nmQIqmYZcvPAoV9vP +gKCy7DeAPrCZ7Cpso0IwQDAOBgNVHQ8BAf8EBAMCAoQwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUJkWeKMencxgUuV4Z/LJEOLObgW8wBQYDK2VwA0EAgbZjKA+x +Y9WbE3KlmLCArDzXOxV288li/HYgx00kVvIJXDOtuI+ujTmMxSL6/qQIm2/3QkeF +4ZBiHAo+qb00AQ== +-----END CERTIFICATE----- diff --git a/offlineauth/test/logdata/dropped.csv b/offlineauth/test/logdata/dropped.csv new file mode 100644 index 00000000..e69de29b diff --git a/offlineauth/test/logdata/invalid.gob b/offlineauth/test/logdata/invalid.gob new file mode 100644 index 00000000..54252ed9 Binary files /dev/null and b/offlineauth/test/logdata/invalid.gob differ diff --git a/offlineauth/test/logdata/valid.gob b/offlineauth/test/logdata/valid.gob new file mode 100644 index 00000000..47110d30 Binary files /dev/null and b/offlineauth/test/logdata/valid.gob differ diff --git a/offlineauth/test/rainsdeleg_test.go b/offlineauth/test/rainsdeleg_test.go new file mode 100644 index 00000000..f89485eb --- /dev/null +++ b/offlineauth/test/rainsdeleg_test.go @@ -0,0 +1,656 @@ +package test + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/json" + "fmt" + logger "github.com/inconshreveable/log15" + "github.com/robinburkhard/rainsdeleg/ca" + "github.com/robinburkhard/rainsdeleg/checkerExtension" + "github.com/robinburkhard/rainsdeleg/child" + "github.com/robinburkhard/rainsdeleg/common" + "github.com/robinburkhard/rainsdeleg/keyManager" + "github.com/robinburkhard/rainsdeleg/parent" + "io/ioutil" + random "math/rand" + "os" + "testing" + "time" +) + +const ( + MAP_ADDRESS = "172.18.0.5:8094" + CA_ADDRESS = "localhost:10000" + CHECKER_ADDRESS = "localhost:10001" + LOG_ADDRESS = "172.18.0.3:8090" + MAP_PK_PATH = "testdata/mappk1.pem" + LOG_PK_PATH = "testdata/logpk1.pem" + MAP_ID = 2727696932843049039 + LOG_ID = 2110187651566808891 +) + +func TestNewDlgEd25519Keys(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + ca_conf, _ := ca.LoadConfig("testdata/configs/caconfig.conf") + parent_conf, _ := parent.LoadConfig("testdata/configs/ch_parentconfig.conf") + checker_conf, _ := checkerExtension.LoadConfig("testdata/configs/checkerconfig.conf") + + ca := ca.NewCA(ca_conf) + go ca.RunServer("localhost:10000") + parent := parent.NewParent(parent_conf) + checker := checkerExtension.NewChecker(checker_conf) + go checker.RunServer("localhost:10001") + + _, childPrivKey, _ := ed25519.GenerateKey(rand.Reader) + random.Seed(time.Now().UnixNano()) + testid := fmt.Sprint(random.Intn(10000)) + csrbytes, _ := child.CreateCSR("test"+testid+"."+parent.Certificate.DNSNames[0], "", childPrivKey) + + _, err := parent.NewDlg(csrbytes, true) + if err != nil { + t.Errorf("NewDlg failed") + } + + time.Sleep(time.Second) + + _, err = parent.NewDlg(csrbytes, true) + if err == nil { + t.Errorf("Parent NewDlg not blocked") + } + +} + +func TestNewDlgRSAKeys(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + ca_conf, _ := ca.LoadConfig("testdata/configs/ca2config.conf") + parent_conf, _ := parent.LoadConfig("testdata/configs/com_parentconfig.conf") + checker_conf, _ := checkerExtension.LoadConfig("testdata/configs/checkerconfig.conf") + + ca := ca.NewCA(ca_conf) + go ca.RunServer("localhost:10000") + parent := parent.NewParent(parent_conf) + checker := checkerExtension.NewChecker(checker_conf) + go checker.RunServer("localhost:10001") + + childPrivKey, _ := rsa.GenerateKey(rand.Reader, 2048) + random.Seed(time.Now().UnixNano()) + testid := fmt.Sprint(random.Intn(10000)) + csrbytes, _ := child.CreateCSR("test"+testid+"."+parent.Certificate.DNSNames[0], "", childPrivKey) + + _, err := parent.NewDlg(csrbytes, true) + if err != nil { + t.Errorf("NewDlg failed") + } + time.Sleep(time.Second) + _, err = parent.NewDlg(csrbytes, true) + if err == nil { + t.Errorf("Parent NewDlg not blocked") + } + +} + +func TestNewDlgReNewDlgKeyChangeDlg(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + ca_conf, _ := ca.LoadConfig("testdata/configs/ca2config.conf") + parent_conf, _ := parent.LoadConfig("testdata/configs/ch_parentconfig.conf") + checker_conf, _ := checkerExtension.LoadConfig("testdata/configs/checkerconfig.conf") + + ca := ca.NewCA(ca_conf) + go ca.RunServer("localhost:10000") + parent := parent.NewParent(parent_conf) + checker := checkerExtension.NewChecker(checker_conf) + go checker.RunServer("localhost:10001") + + _, childPrivKey, _ := ed25519.GenerateKey(rand.Reader) + random.Seed(time.Now().UnixNano()) + testid := fmt.Sprint(random.Intn(10000)) + csrbytes, _ := child.CreateCSR("test"+testid+"."+parent.Certificate.DNSNames[0], "", childPrivKey) + + childCert, err := parent.NewDlg(csrbytes, true) + //common.StoreCertificatePEM("testrun.cert", childCert) + if err != nil { + t.Errorf("NewDlg failed %s", err) + return + } + + time.Sleep(time.Second) + + _, err = parent.NewDlg(csrbytes, true) + if err == nil { + t.Errorf("Parent NewDlg not blocked") + } + + childCertParsed, _ := x509.ParseCertificate(childCert) + renewedCert, err := child.ReNewDlg(childCertParsed, childPrivKey, "localhost:10000", "localhost:10001") + if err != nil { + t.Errorf("Child ReNewDlg failed") + return + } + + renewedCertParsed, _ := x509.ParseCertificate(renewedCert) + newKey1, _ := rsa.GenerateKey(rand.Reader, 2048) + + newKey1Cert, err := child.KeyChangeDlg(renewedCertParsed, childPrivKey, newKey1, "localhost:10000", "localhost:10001") + if err != nil { + t.Errorf("Key Change failed") + return + } + + newKey1CertParsed, _ := x509.ParseCertificate(newKey1Cert) + _, newKey2, _ := ed25519.GenerateKey(rand.Reader) + + _, err = child.KeyChangeDlg(newKey1CertParsed, newKey1, newKey2, "localhost:10000", "localhost:10001") + if err != nil { + t.Errorf("Key Change failed") + return + } + +} +func TestFull(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + var alg = "Ed25519" + + //create a CA: + ca_alg := alg + ca_key_path := "testfulldata/ca.key" + ca_cert_path := "testfulldata/ca.cert" + keyManager.CreateEd25519Key(ca_key_path) + keyManager.CreateSelfSignedCACertificate(ca_alg, ca_key_path, ca_cert_path) + cert, _ := common.LoadCertificatePEM(ca_cert_path) + common.StoreCertificatePEM("testfulldata/roots/ca.cert", cert.Raw) + + ca_config := ca.Config{ + PrivateKeyAlgorithm: ca_alg, + PrivateKeyPath: ca_key_path, + CertificatePath: ca_cert_path, + MapServerAddress: MAP_ADDRESS, + MapServerPublicKeyPath: MAP_PK_PATH, + MapId: MAP_ID, + ServerAddress: CA_ADDRESS, + RootCertsPath: "testfulldata/roots/", + } + CA := ca.NewCA(ca_config) + go CA.RunServer(CA_ADDRESS) + + checker_config := checkerExtension.Config{ + LogID: LOG_ID, + LogAddress: LOG_ADDRESS, + LogPkeyPath: LOG_PK_PATH, + MapID: MAP_ID, + MapAddress: MAP_ADDRESS, + MapPkeyPath: MAP_PK_PATH, + RootCertsPath: "testfulldata/roots/", + ServerAddress: CHECKER_ADDRESS, + } + CHECKER := checkerExtension.NewChecker(checker_config) + go CHECKER.RunServer(CHECKER_ADDRESS) + + // random test number + random.Seed(time.Now().UnixNano()) + testid := fmt.Sprint(random.Intn(10000)) + + //create root parent zone with no authentication (instead of using dnssec) + root_alg := alg + root_key_path := "testfulldata/root.key" + keyManager.CreateEd25519Key(root_key_path) + root_config := parent.Config{ + Zone: "rhine", + AuthenticationType: "NOAUTH", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: root_alg, + PrivateKeyPath: root_key_path, + CertificatePath: "", + CAAddress: CA_ADDRESS, + OutputDir: "", + } + ROOT := parent.NewParent(root_config) + + tld_alg := alg + tld_key_path := "testfulldata/tld.key" + keyManager.CreateEd25519Key(tld_key_path) + tld_key, _ := common.LoadPrivateKeyEd25519(tld_key_path) + + tld_zone := "tld" + testid + "." + root_config.Zone + tld_csr, _ := child.CreateCSR(tld_zone, "", tld_key) + + common.StoreCertificateRequestPEM("testfulldata/debugcsr.csr", tld_csr) + + tld_cert, err := ROOT.NewDlg(tld_csr, true) + if err != nil { + fmt.Println(err) + t.Errorf("Root NewDlg failed") + return + } + + tld_cert_parsed, _ := x509.ParseCertificate(tld_cert) + fmt.Println(tld_cert_parsed.Extensions) + + tld_cert_path := "testfulldata/tld.cert" + common.StoreCertificatePEM(tld_cert_path, tld_cert) + + tld_config := parent.Config{ + Zone: tld_zone, + AuthenticationType: "certificate", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: tld_alg, + PrivateKeyPath: tld_key_path, + CertificatePath: tld_cert_path, + CAAddress: CA_ADDRESS, + OutputDir: "", + } + TLD := parent.NewParent(tld_config) + + _, SLDKey, _ := ed25519.GenerateKey(rand.Reader) + SLDcsrbytes, _ := child.CreateCSR("sld"+testid+"."+TLD.Certificate.DNSNames[0], "", SLDKey) + + SLDcert, err := TLD.NewDlg(SLDcsrbytes, true) + if err != nil { + t.Errorf("SLD NewDlg failed %s", err) + return + } + common.StoreCertificatePEM("testfulldata/sld.cert", SLDcert) + + time.Sleep(time.Second * 2) + + _, err = TLD.NewDlg(SLDcsrbytes, true) + if err == nil { + t.Errorf("TLD NewDlg for SLD not blocked") + return + } + + sldCertParsed, _ := x509.ParseCertificate(SLDcert) + renewedCert, err := child.ReNewDlg(sldCertParsed, SLDKey, CA_ADDRESS, CHECKER_ADDRESS) + if err != nil { + t.Errorf("SLD ReNewDlg failed") + return + } + + renewedCertParsed, _ := x509.ParseCertificate(renewedCert) + newKey1, _ := rsa.GenerateKey(rand.Reader, 2048) + + newKey1Cert, err := child.KeyChangeDlg(renewedCertParsed, SLDKey, newKey1, CA_ADDRESS, CHECKER_ADDRESS) + if err != nil { + t.Errorf("Key Change failed") + return + } + + newKey1CertParsed, _ := x509.ParseCertificate(newKey1Cert) + _, newKey2, _ := ed25519.GenerateKey(rand.Reader) + + _, err = child.KeyChangeDlg(newKey1CertParsed, newKey1, newKey2, CA_ADDRESS, CHECKER_ADDRESS) + if err != nil { + t.Errorf("Key Change failed") + return + } + +} + +func TestRevoke(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + var alg = "Ed25519" + + //create a CA: + ca_alg := alg + ca_key_path := "testfulldata/ca.key" + ca_cert_path := "testfulldata/ca.cert" + keyManager.CreateEd25519Key(ca_key_path) + keyManager.CreateSelfSignedCACertificate(ca_alg, ca_key_path, ca_cert_path) + cert, _ := common.LoadCertificatePEM(ca_cert_path) + common.StoreCertificatePEM("testfulldata/roots/ca.cert", cert.Raw) + + ca_config := ca.Config{ + PrivateKeyAlgorithm: ca_alg, + PrivateKeyPath: ca_key_path, + CertificatePath: ca_cert_path, + MapServerAddress: MAP_ADDRESS, + MapServerPublicKeyPath: MAP_PK_PATH, + MapId: MAP_ID, + ServerAddress: CA_ADDRESS, + RootCertsPath: "testfulldata/roots/", + } + CA := ca.NewCA(ca_config) + go CA.RunServer(CA_ADDRESS) + + checker_config := checkerExtension.Config{ + LogID: LOG_ID, + LogAddress: LOG_ADDRESS, + LogPkeyPath: LOG_PK_PATH, + MapID: MAP_ID, + MapAddress: MAP_ADDRESS, + MapPkeyPath: MAP_PK_PATH, + RootCertsPath: "testfulldata/roots/", + ServerAddress: CHECKER_ADDRESS, + } + CHECKER := checkerExtension.NewChecker(checker_config) + go CHECKER.RunServer(CHECKER_ADDRESS) + + // random test number + random.Seed(time.Now().UnixNano()) + testid := fmt.Sprint(random.Intn(10000)) + + //create root parent zone with no authentication (instead of using dnssec) + root_alg := alg + root_key_path := "testfulldata/root.key" + keyManager.CreateEd25519Key(root_key_path) + root_config := parent.Config{ + Zone: "rhine", + AuthenticationType: "NOAUTH", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: root_alg, + PrivateKeyPath: root_key_path, + CertificatePath: "", + CAAddress: CA_ADDRESS, + OutputDir: "", + } + ROOT := parent.NewParent(root_config) + + tld_alg := alg + tld_key_path := "testfulldata/tld.key" + keyManager.CreateEd25519Key(tld_key_path) + tld_key, _ := common.LoadPrivateKeyEd25519(tld_key_path) + + tld_zone := "tld" + testid + "." + root_config.Zone + tld_csr, _ := child.CreateCSR(tld_zone, "", tld_key) + + common.StoreCertificateRequestPEM("testfulldata/debugcsr.csr", tld_csr) + + tld_cert, err := ROOT.NewDlg(tld_csr, true) + if err != nil { + fmt.Println(err) + t.Errorf("Root NewDlg failed") + return + } + + tld_cert_parsed, _ := x509.ParseCertificate(tld_cert) + fmt.Println(tld_cert_parsed.Extensions) + + tld_cert_path := "testfulldata/tld.cert" + common.StoreCertificatePEM(tld_cert_path, tld_cert) + + tld_config := parent.Config{ + Zone: tld_zone, + AuthenticationType: "certificate", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: tld_alg, + PrivateKeyPath: tld_key_path, + CertificatePath: tld_cert_path, + CAAddress: CA_ADDRESS, + OutputDir: "", + } + TLD := parent.NewParent(tld_config) + + _, SLDKey, _ := ed25519.GenerateKey(rand.Reader) + SLDcsrbytes, _ := child.CreateCSR("sld"+testid+"."+TLD.Certificate.DNSNames[0], "", SLDKey) + + SLDcert, err := TLD.NewDlg(SLDcsrbytes, true) + if err != nil { + t.Errorf("SLD NewDlg failed %s", err) + return + } + common.StoreCertificatePEM("testfulldata/sld.cert", SLDcert) + + //revoke sld cert + SLDCertParsed, _ := x509.ParseCertificate(SLDcert) + err = child.RevokeDlg(SLDCertParsed, SLDKey, CHECKER_ADDRESS) + if err != nil { + t.Errorf("Revoke failed %s", err) + return + } + + time.Sleep(time.Second * 2) + + _, err = TLD.NewDlg(SLDcsrbytes, true) + if err != nil { + t.Errorf("TLD NewDlg still blocked (should not because of revocation)") + return + } + +} + +func TestCreateDemoFiles(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + var demotld = "ch1" + + var alg = "Ed25519" + + //create a CA: + ca_alg := alg + ca_key_path := "testfulldata/ca.key" + ca_cert_path := "testfulldata/ca.cert" + keyManager.CreateEd25519Key(ca_key_path) + keyManager.CreateSelfSignedCACertificate(ca_alg, ca_key_path, ca_cert_path) + cert, _ := common.LoadCertificatePEM(ca_cert_path) + common.StoreCertificatePEM("testfulldata/roots/ca.cert", cert.Raw) + + ca_config := ca.Config{ + PrivateKeyAlgorithm: ca_alg, + PrivateKeyPath: ca_key_path, + CertificatePath: ca_cert_path, + MapServerAddress: MAP_ADDRESS, + MapServerPublicKeyPath: MAP_PK_PATH, + MapId: MAP_ID, + ServerAddress: CA_ADDRESS, + RootCertsPath: "testfulldata/roots/", + } + + ca_conf_file, _ := json.MarshalIndent(ca_config, "", " ") + _ = ioutil.WriteFile("testfulldata/ca.conf", ca_conf_file, 0644) + + CA := ca.NewCA(ca_config) + go CA.RunServer(CA_ADDRESS) + + checker_config := checkerExtension.Config{ + LogID: LOG_ID, + LogAddress: LOG_ADDRESS, + LogPkeyPath: LOG_PK_PATH, + MapID: MAP_ID, + MapAddress: MAP_ADDRESS, + MapPkeyPath: MAP_PK_PATH, + RootCertsPath: "testfulldata/roots/", + ServerAddress: CHECKER_ADDRESS, + } + + checker_conf_file, _ := json.MarshalIndent(checker_config, "", " ") + _ = ioutil.WriteFile("testfulldata/checker.conf", checker_conf_file, 0644) + + CHECKER := checkerExtension.NewChecker(checker_config) + go CHECKER.RunServer(CHECKER_ADDRESS) + + time.Sleep(time.Second * 2) + + // random test number + //random.Seed(time.Now().UnixNano()) + //testid := fmt.Sprint(random.Intn(10000)) + + //create root parent zone with no authentication (instead of using dnssec) + root_alg := alg + root_key_path := "testfulldata/root.key" + keyManager.CreateEd25519Key(root_key_path) + root_config := parent.Config{ + Zone: "rhine", + AuthenticationType: "NOAUTH", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: root_alg, + PrivateKeyPath: root_key_path, + CertificatePath: "", + CAAddress: CA_ADDRESS, + OutputDir: "testfulldata/", + } + + root_conf_file, _ := json.MarshalIndent(root_config, "", " ") + _ = ioutil.WriteFile("testfulldata/root.conf", root_conf_file, 0644) + + ROOT := parent.NewParent(root_config) + + tld_alg := alg + tld_key_path := "testfulldata/tld.key" + keyManager.CreateEd25519Key(tld_key_path) + tld_key, _ := common.LoadPrivateKeyEd25519(tld_key_path) + + tld_zone := demotld + ".rhine" + tld_csr, _ := child.CreateCSR(tld_zone, "", tld_key) + + fmt.Println("len csr", len(tld_csr)) + common.StoreCertificateRequestPEM("testfulldata/debugcsr.csr", tld_csr) + + tld_cert, err := ROOT.NewDlg(tld_csr, true) + if err != nil { + fmt.Println(err) + t.Errorf("Root NewDlg failed") + return + } + + fmt.Println("TLD Cert Size Ed25519", len(tld_cert)) + + tld_cert_parsed, _ := x509.ParseCertificate(tld_cert) + fmt.Println(tld_cert_parsed.Extensions) + + tld_cert_path := "testfulldata/tld.cert" + common.StoreCertificatePEM(tld_cert_path, tld_cert) + + tld_config := parent.Config{ + Zone: tld_zone, + AuthenticationType: "certificate", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: tld_alg, + PrivateKeyPath: tld_key_path, + CertificatePath: tld_cert_path, + CAAddress: CA_ADDRESS, + OutputDir: "testfulldata/", + } + + tld_conf_file, _ := json.MarshalIndent(tld_config, "", " ") + _ = ioutil.WriteFile("testfulldata/tld.conf", tld_conf_file, 0644) + + //TLD := parent.NewParent(tld_config) + +} + +func TestCreateDemoFiles2(t *testing.T) { + logger.Root().SetHandler(logger.StreamHandler(os.Stdout, logger.TerminalFormat())) + + var demotld = "ch" + + var alg = "Ed25519" + + //create a CA: + ca_alg := alg + ca_key_path := "demo/ca.key" + ca_cert_path := "demo/ca.cert" + keyManager.CreateEd25519Key(ca_key_path) + keyManager.CreateSelfSignedCACertificate(ca_alg, ca_key_path, ca_cert_path) + cert, _ := common.LoadCertificatePEM(ca_cert_path) + common.StoreCertificatePEM("demo/roots/ca.cert", cert.Raw) + + ca_config := ca.Config{ + PrivateKeyAlgorithm: ca_alg, + PrivateKeyPath: ca_key_path, + CertificatePath: ca_cert_path, + MapServerAddress: MAP_ADDRESS, + MapServerPublicKeyPath: MAP_PK_PATH, + MapId: MAP_ID, + ServerAddress: CA_ADDRESS, + RootCertsPath: "demo/roots/", + } + + ca_conf_file, _ := json.MarshalIndent(ca_config, "", " ") + _ = ioutil.WriteFile("demo/ca.conf", ca_conf_file, 0644) + + CA := ca.NewCA(ca_config) + go CA.RunServer(CA_ADDRESS) + + checker_config := checkerExtension.Config{ + LogID: LOG_ID, + LogAddress: LOG_ADDRESS, + LogPkeyPath: LOG_PK_PATH, + MapID: MAP_ID, + MapAddress: MAP_ADDRESS, + MapPkeyPath: MAP_PK_PATH, + RootCertsPath: "demo/roots/", + ServerAddress: CHECKER_ADDRESS, + } + + checker_conf_file, _ := json.MarshalIndent(checker_config, "", " ") + _ = ioutil.WriteFile("demo/checker.conf", checker_conf_file, 0644) + + CHECKER := checkerExtension.NewChecker(checker_config) + go CHECKER.RunServer(CHECKER_ADDRESS) + + time.Sleep(time.Second * 2) + + // random test number + //random.Seed(time.Now().UnixNano()) + //testid := fmt.Sprint(random.Intn(10000)) + + //create root parent zone with no authentication (instead of using dnssec) + root_alg := alg + root_key_path := "demo/root.key" + keyManager.CreateEd25519Key(root_key_path) + root_config := parent.Config{ + Zone: "rains", + AuthenticationType: "NOAUTH", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: root_alg, + PrivateKeyPath: root_key_path, + CertificatePath: "", + CAAddress: CA_ADDRESS, + OutputDir: "demo/", + } + + root_conf_file, _ := json.MarshalIndent(root_config, "", " ") + _ = ioutil.WriteFile("demo/root.conf", root_conf_file, 0644) + + ROOT := parent.NewParent(root_config) + + tld_alg := alg + tld_key_path := "demo/" + demotld + ".key" + keyManager.CreateEd25519Key(tld_key_path) + tld_key, _ := common.LoadPrivateKeyEd25519(tld_key_path) + + tld_zone := demotld + ".rains" + tld_csr, _ := child.CreateCSR(tld_zone, "", tld_key) + + fmt.Println("len csr", len(tld_csr)) + common.StoreCertificateRequestPEM("demo/debugcsr.csr", tld_csr) + + tld_cert, err := ROOT.NewDlg(tld_csr, true) + if err != nil { + fmt.Println(err) + t.Errorf("Root NewDlg failed") + return + } + + fmt.Println("TLD Cert Size Ed25519", len(tld_cert)) + + tld_cert_parsed, _ := x509.ParseCertificate(tld_cert) + fmt.Println(tld_cert_parsed.Extensions) + + tld_cert_path := "demo/" + demotld + ".cert" + common.StoreCertificatePEM(tld_cert_path, tld_cert) + + tld_config := parent.Config{ + Zone: tld_zone, + AuthenticationType: "certificate", + LogCheckerExtAddress: CHECKER_ADDRESS, + PrivateKeyAlgorithm: tld_alg, + PrivateKeyPath: tld_key_path, + CertificatePath: tld_cert_path, + CAAddress: CA_ADDRESS, + OutputDir: "demo/", + } + + tld_conf_file, _ := json.MarshalIndent(tld_config, "", " ") + _ = ioutil.WriteFile("demo/"+demotld+".conf", tld_conf_file, 0644) + + //TLD := parent.NewParent(tld_config) + +} diff --git a/offlineauth/test/testdata/certs/CA2Cert.pem b/offlineauth/test/testdata/certs/CA2Cert.pem new file mode 100644 index 00000000..0ff818dc --- /dev/null +++ b/offlineauth/test/testdata/certs/CA2Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBMDCB46ADAgECAgEBMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMTE1MjAzOTExWhcNMjIxMTA2MjAzOTExWjAgMR4wHAYD +VQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwKjAFBgMrZXADIQBMguNWaDaEfNux +ktPz98+irAJjvhTgNFtYoszyP6HbX6NCMEAwDgYDVR0PAQH/BAQDAgKEMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOe+AYbokwTO8t7Q/oM/Dssd1mOeMAUGAytl +cANBANST2xcaKcjXu8qiRziWWCf3Cmb8jCUIxv7UFmoHHrKN/WoI+1XlvPuzh9nG +fl2GXm7/tBCE1vwdxFofin9HOQk= +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/certs/CACert.pem b/offlineauth/test/testdata/certs/CACert.pem new file mode 100644 index 00000000..f22b3eab --- /dev/null +++ b/offlineauth/test/testdata/certs/CACert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMTA3MjExMTA4WhcNMjIxMDI5MjExMTA4 +WjAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCWf0HP1kGNKQSnhfB74lQqRFH7CogNjDzrfT1P +FJvJfyCTfpsGdEEpUKSIzkhNrxCZqiGdmICnW9rAAMDGAmUw1dkiqBV7gmyzW93N +bk7fTf//a6bCeyb+oDcSpyad8jGo3edcWTaJj2pqJPwxjx+1ONPar1babmlfJ9nI +fEb4jG/nQd6eY8DZxRjRRViPIOeQc1yEpO7FKhQJd6Zj0xy4VBkMZEcZuIwZeHMb +VHBbicQZmmBnjUCv3ArYAQARaDrh9bdwITB0pAuO2P/BS32/Ic78NhrFgaC6elVM +ik0kD8M6gLqsqSlb8BWJVhkIFeTOIvtYur/WwSXFg0J5tQqvAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIChDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTSgQ1hCLQ1 +nHDbzXxaW+k9IxUwDTANBgkqhkiG9w0BAQsFAAOCAQEAG+m8AFQGSBtNwL/1q5cB +GTxBGW2E8sgQ55SGvG//S1FL5CymPsby4xQHf9q/ZHo/R5JTE8z5n0IxWZKRjywy +CfRrqEMY3ftqaYGQ/Qi6CLMhBCB/S623RBl4vG7Sp1jJkURcx3N4l9SWIdRfMoJW +MPXYNhYPiWsPHq7+PrzAfPeuzWyQ7Tbbldz43VIlG8JIo9PnCPxwcHcRN98FVjtw +M7DGhmBXEeddaiHcqcgJwoY92744xCWJLOUz57coVudVkNTQHxNGTommad/xMKz3 +40zH2DoSkObxGfaJblsMvgQa0u2e89GbBShlPK3gXKLIxvIJJCQ+wYTLwdY2XsTW +mw== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/certs/ch_Cert.pem b/offlineauth/test/testdata/certs/ch_Cert.pem new file mode 100644 index 00000000..609b85e3 --- /dev/null +++ b/offlineauth/test/testdata/certs/ch_Cert.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2DCBwaADAgECAgEAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFVJBSU5T +IEVYQU1QTEUgUk9PVCBDQTAeFw0yMTExMDcyMTQwMjBaFw0yMjEwMjkyMTQwMjBa +MAAwKjAFBgMrZXADIQBeZ795eOkG8W8f32gQ62eIJ3BUXZUzm9OsrgdWDn08xKM4 +MDYwHwYDVR0jBBgwFoAU0oENYQi0NZxw2818WlvpPSMVMA0wEwYDVR0RAQH/BAkw +B4IFY2gudXMwDQYJKoZIhvcNAQELBQADggEBABoTnJhydNhZuf6Rex/evmjsewjX +FdAHoHGbuipNgJdMza/+1o2EptB2S6/0OSKonkZkRQ3Jswl+ZL+u0UbClqorFuyA +L4V+H+iXtKVceEdhfS+2G7ZqyC2BsPa/re9tP4xWeDPVyK+xFLKgUa/60qLw7nmu +9JUZ4wkKsgmMxXXGTUf/4DmS9jcnHuB69GBxBvRcr9tqCGGrOP+FH7jXoUetB/V+ +s+erVlfuK3NIoC6y7G5zw3fkUdNEqKIkAQ14o6iyMjE1N6MpbNtr73BL1G7s7YoT +If7NGOwYIyGGoB8fkIKCTczma0VB50+WMo8TjJbG8Ej8sbURRMOO86vI/HQ= +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/certs/com_Cert.pem b/offlineauth/test/testdata/certs/com_Cert.pem new file mode 100644 index 00000000..5b7700d8 --- /dev/null +++ b/offlineauth/test/testdata/certs/com_Cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC1DCCAbygAwIBAgIBADANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMTE1MjAyNTM2WhcNMjIxMTA2MjAyNTM2 +WjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsHlEohuvEpLfw8o4 +Gi7K03FejnIb0pPHw4ljPv75N/vQfzYfMQCki04j56F9Xbgah05UXRHMyC740bJe +JHQmGhGnnO2JRa9lU2FgGEk9byJop4vtaKq93AgbzlPSkSb9HlHMlzSwSPgwnYWY +gBFhzQ1TjAw9SA+1vT+xV0MWCIqX6NFOlH6WKHJtNIT0dIa0h4BM3rtNUfLzZm2X +NioV/W+ejm4HjMvM5onq+IL1ipFPBEZpzynMS9Pye78/viIOzMd3JniAqx3FL/LX ++vAjmxOYTZFVSUGVAm8XpBwgBWKs6vG5fSi42iPYkeJeVR5IdFZ9Lyo+c0qv0xfa +B8EBOwIDAQABozkwNzAfBgNVHSMEGDAWgBTSgQ1hCLQ1nHDbzXxaW+k9IxUwDTAU +BgNVHREBAf8ECjAIggZjb20udXMwDQYJKoZIhvcNAQELBQADggEBACuym3ksttO6 +sbZv0b8pNEQJmKrLWcYQaDu7kxWlgMnJXvRU51pPs+nqUj7EJMnFyNFNKyrLyntu +a1hiMKkpE/cwpzu05TfP6Yw/rK7k/CwufVbuqDZBilSvGfHM5APVkdHOUgQIip0Q +9l/dHV8SGJKbgLKrYBzjrt8s7j3edt1yAcODSloreGL2iKwuwvRbLptfPeL10Yot +HU5IyVbml2E/7b6gfUKH4HXDWNYKUuLPG9lYOPaRU1tFDyHjyTPT3xZzZfF76v85 ++nnB6OhshtZFinsLHlxwD4B79iNJErzZJPftcqB1Y5NI5HEc6+B4WUidJnk9eYOe +iUonFpV3sXo= +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/certs/tld1.RHINE_Cert.pem b/offlineauth/test/testdata/certs/tld1.RHINE_Cert.pem new file mode 100644 index 00000000..d023d3b4 --- /dev/null +++ b/offlineauth/test/testdata/certs/tld1.RHINE_Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBQTCB9KADAgECAgEAMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMjAzMTU1MDA5WhcNMjIxMTI0MTU1MDA5WjAbMRkwFwYD +VQQDExBSSElORTp0bGQxLlJISU5FMCowBQYDK2VwAyEASYG79apsin3Ripgkj14o +U54Zma4OJQUJumffjMH6X0ajWDBWMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E +AjAAMB8GA1UdIwQYMBaAFOe+AYbokwTO8t7Q/oM/Dssd1mOeMBUGA1UdEQQOMAyC +CnRsZDEuUkhJTkUwBQYDK2VwA0EAtgNQIyz0MLe7NApIwBY2nPc74w6VkM4LlUTx +KvTPdjUp5lvfABY7hOeoYFCUlI9bOlFrNfoZ5BQpaCKQKXjwBw== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/configs/ca2config.conf b/offlineauth/test/testdata/configs/ca2config.conf new file mode 100644 index 00000000..10e9b223 --- /dev/null +++ b/offlineauth/test/testdata/configs/ca2config.conf @@ -0,0 +1,10 @@ +{ + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testdata/keys/CA2Key.pem", + "CertificatePath": "testdata/certs/CA2Cert.pem", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "testdata/mappk1.pem", + "MapId": 5250323035397941290, + "ServerAddress" : "localhost:10000", + "RootCertsPath" : "testdata/roots/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/caconfig.conf b/offlineauth/test/testdata/configs/caconfig.conf new file mode 100644 index 00000000..d51c1a09 --- /dev/null +++ b/offlineauth/test/testdata/configs/caconfig.conf @@ -0,0 +1,10 @@ +{ + "PrivateKeyAlgorithm": "RSA", + "PrivateKeyPath": "testdata/keys/CAKey.pem", + "CertificatePath": "testdata/certs/CACert.pem", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "testdata/mappk1.pem", + "MapId": 5250323035397941290, + "ServerAddress" : "localhost:10000", + "RootCertsPath" : "testdata/roots/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/ch_parentconfig.conf b/offlineauth/test/testdata/configs/ch_parentconfig.conf new file mode 100644 index 00000000..cf7b9746 --- /dev/null +++ b/offlineauth/test/testdata/configs/ch_parentconfig.conf @@ -0,0 +1,10 @@ +{ + "Zone": "ch.us", + "AuthenticationType": "certificate", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testdata/keys/ch_Key.pem", + "CertificatePath": "testdata/certs/ch_Cert.pem", + "LogCheckerExtAddress": "localhost:10001", + "CAAddress": "localhost:10000", + "OutputDir": "testdata/ch.out/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/checkerconfig.conf b/offlineauth/test/testdata/configs/checkerconfig.conf new file mode 100644 index 00000000..d5c63a85 --- /dev/null +++ b/offlineauth/test/testdata/configs/checkerconfig.conf @@ -0,0 +1,10 @@ +{ + "LogID": 893878204519017005, + "LogAddress": "172.18.0.3:8090", + "LogPkeyPath": "testdata/logpk1.pem", + "MapID": 5250323035397941290, + "MapAddress": "172.18.0.5:8094", + "MapPkeyPath": "testdata/mappk1.pem", + "RootCertsPath" : "testdata/roots/", + "ServerAddress" : "localhost:10001" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/com_parentconfig.conf b/offlineauth/test/testdata/configs/com_parentconfig.conf new file mode 100644 index 00000000..e393bbc6 --- /dev/null +++ b/offlineauth/test/testdata/configs/com_parentconfig.conf @@ -0,0 +1,10 @@ +{ + "Zone": "com.us", + "AuthenticationType": "certificate", + "PrivateKeyAlgorithm": "RSA", + "PrivateKeyPath": "testdata/keys/com_Key.pem", + "CertificatePath": "testdata/certs/com_Cert.pem", + "LogCheckerExtAddress": "localhost:10001", + "CAAddress": "localhost:10000", + "OutputDir": "testdata/com.out/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/root_parentconfig.conf b/offlineauth/test/testdata/configs/root_parentconfig.conf new file mode 100644 index 00000000..f347df31 --- /dev/null +++ b/offlineauth/test/testdata/configs/root_parentconfig.conf @@ -0,0 +1,10 @@ +{ + "Zone": ".RHINE", + "AuthenticationType": "NOAUTH", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testdata/keys/root_Key.pem", + "CertificatePath": "", + "LogCheckerExtAddress": "localhost:10001", + "CAAddress": "localhost:10000", + "OutputDir": "testdata/rootout/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/configs/tld1.conf b/offlineauth/test/testdata/configs/tld1.conf new file mode 100644 index 00000000..f7efb4ee --- /dev/null +++ b/offlineauth/test/testdata/configs/tld1.conf @@ -0,0 +1,10 @@ +{ + "Zone": "tld1.RHINE", + "AuthenticationType": "certificate", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testdata/keys/tld.pem", + "CertificatePath": "testdata/certs/ch_Cert.pem", + "LogCheckerExtAddress": "localhost:10001", + "CAAddress": "localhost:10000", + "OutputDir": "testdata/ch.out/" +} \ No newline at end of file diff --git a/offlineauth/test/testdata/keys/CA2Key.pem b/offlineauth/test/testdata/keys/CA2Key.pem new file mode 100644 index 00000000..12e9d9e2 --- /dev/null +++ b/offlineauth/test/testdata/keys/CA2Key.pem @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +DECYjIa2nXFLPUpxVpzrexOc+g93lSUFUJdtvltInXRMguNWaDaEfNuxktPz98+i +rAJjvhTgNFtYoszyP6HbXw== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/testdata/keys/CAKey.pem b/offlineauth/test/testdata/keys/CAKey.pem new file mode 100644 index 00000000..27a78f3e --- /dev/null +++ b/offlineauth/test/testdata/keys/CAKey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAln9Bz9ZBjSkEp4Xwe+JUKkRR+wqIDYw86309TxSbyX8gk36b +BnRBKVCkiM5ITa8QmaohnZiAp1vawADAxgJlMNXZIqgVe4Jss1vdzW5O303//2um +wnsm/qA3EqcmnfIxqN3nXFk2iY9qaiT8MY8ftTjT2q9W2m5pXyfZyHxG+Ixv50He +nmPA2cUY0UVYjyDnkHNchKTuxSoUCXemY9McuFQZDGRHGbiMGXhzG1RwW4nEGZpg +Z41Ar9wK2AEAEWg64fW3cCEwdKQLjtj/wUt9vyHO/DYaxYGgunpVTIpNJA/DOoC6 +rKkpW/AViVYZCBXkziL7WLq/1sElxYNCebUKrwIDAQABAoIBAH+axyKCeHJIJTol +xxJDhTmRVDGXbGSQU9cYCbPTtYPT1rs4zhla2SU+y0N0JLo5hcnFB1uowu0kZQYH +nWxG+6W8rK9F9XET1Tb+3cIhlZ6hdD4N+QdNhHLBRfD66TNi99hGzrTur99TStdV +JMCgqjHuTTNPGEV8+LtF/tKPDV4P6LZ7d8JQjoZEfJcfNwXHmdvtgA0Udl63PE3X +dwQCBgycqe61x3DYFTeVKXccmczkmWrhU9iC1QIEL+JFyw5nWxzjiGaPQrPqvQAc +vYAus9ZxhqZU+5eXpoCn++ZI6bWDVOW03XI1YsO6yDjH6uVvBMALCh4imhsKCYOy +kymmIgECgYEAxFqVLjVZgzW7TfOstdE7IDMDx8BlwJBdZb3Qx0cT8I9xm53pDGV0 +mjQ19glqii4nuxhv3PjHIgC0n7kt3LBBFQJAZXXeYTcSXTuHzTWzkaBlMap8b4+t +NCvA1RmUSGb186fuFZZXHgUOcb0iY4Z5X5yUn6TRKrGCjXQMsZxOUvECgYEAxDai +TctoElc3jdpMbTRI2UK36R4UjzIoLgOeTHKBWx7GFLV3g/Ff2ofRx2NpHvcQoO0k +CFznq4ZGhBQvJHdBWGuecf7el8t5uHKZhPgKYLU7Hejam+ThL1a1+n6RG4XUsfj8 +oKHFAuTvS4xw32L5t+lR3jQcoG8odefHZVGZ958CgYA+ObqnHy8T3tZR+NQV9o23 +QZOEHRvh7545nPLqBEN0a/ED8QIm9IwERmGHbCqASeo7Z54juA9bXj/fkk7Pbmfh +oYoI3VaxFkPSmggKZ2dV0i/fknjG3hB0xRziK64LV92/7ssLuk43bEDMmLSqN7aF +L1kGUrQaxJBsBYf0TWWg8QKBgG6XyLWGf5tO034927P1s1XZ2CUqEjZ/88uzuGao +Z6a/WrBTdBDHXNqkkSYMLzUH1rSN1TBthRrVrStG4SdxnEBFMGJaYIY4ZtwCo+sh +j1/g5ng+RfF2eUIgYqPU8N8NeMvzZhj39T5jYUk42GngtJXniYBv6O64mJqUUHwY +GWtLAoGBAIqPnED1sXxeG8URCNEUzgdTU1iNABE8G2NJeJjajH98hTAQmxvaojkS +EgmkdkNbhcqubiDtaud0Czs6rduGiNSNMiraRrWrVzqnS8BzAdiZKNM/76HhUcvn +ENzJSvtca8PIXbGN6LK/a7aDkT/HpnnydrbyonfuxhsOqVSKNi4Y +-----END RSA PRIVATE KEY----- diff --git a/offlineauth/test/testdata/keys/ch_Key.pem b/offlineauth/test/testdata/keys/ch_Key.pem new file mode 100644 index 00000000..c5fadb18 --- /dev/null +++ b/offlineauth/test/testdata/keys/ch_Key.pem @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +P5l3kVZXJIOkUC5MLu4Qu7Vu8ZkRpVRoGGekn+qrXsReZ795eOkG8W8f32gQ62eI +J3BUXZUzm9OsrgdWDn08xA== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/testdata/keys/com_Key.pem b/offlineauth/test/testdata/keys/com_Key.pem new file mode 100644 index 00000000..e46e64f9 --- /dev/null +++ b/offlineauth/test/testdata/keys/com_Key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAsHlEohuvEpLfw8o4Gi7K03FejnIb0pPHw4ljPv75N/vQfzYf +MQCki04j56F9Xbgah05UXRHMyC740bJeJHQmGhGnnO2JRa9lU2FgGEk9byJop4vt +aKq93AgbzlPSkSb9HlHMlzSwSPgwnYWYgBFhzQ1TjAw9SA+1vT+xV0MWCIqX6NFO +lH6WKHJtNIT0dIa0h4BM3rtNUfLzZm2XNioV/W+ejm4HjMvM5onq+IL1ipFPBEZp +zynMS9Pye78/viIOzMd3JniAqx3FL/LX+vAjmxOYTZFVSUGVAm8XpBwgBWKs6vG5 +fSi42iPYkeJeVR5IdFZ9Lyo+c0qv0xfaB8EBOwIDAQABAoIBAQCZditgCVD6huy9 +1zloU26f5wOCPerB+S8LdIrwukvBCmMqbMc9FsEAP0hr4nwhprqzFUO514PMRUSt +Hj5N1w9XNikbB1mLVtZ3ZsNo+y/IWBTINp+SmIAYOpjrmOsQvOX6msmeZ/wwyFuG +cCnInNT+uur/a5lS9A5n715pcvZTH7hAZ0HOGEIEHa37n5Wty3LLb1qhwqLgRo4R +Ipjz6BZDeYx/x+cUCoF5RQioXreucTejX7DMq4WP9dEDWnbeAVt/RJb9jcGnwsu1 +k/4KPWXBYGs5L3/vKd1PBvXjH2Gts7Xev58Nvlq4kki9cTWHmD/NMYz0mdljQwEM +Zp8lEv9ZAoGBAMdMXJZm0eJs0o5Pa03l+XpyP4UXIl592b6S1lv+WpaoGYf03pZT +TOF4o91MSZV9MtN4orQ5WM5I0TiAKusuliWvONd5dZOloDoCUn+c+0g0ElbL8rZJ +6bdGaNLfnpK8At4A7cQ/0MSG3oL2TAB1LpazhPH5lgElIrEVw+ccFBv9AoGBAOKu +gbonPevii0QGaOxHa9g7LqspOVUo5A09j8GfnVJaYa6dUFOi7rHX+lt3gCU77IkH +EUV5TNRUM2IeowgMJbnLaaUbHnJwSw1bfYjNcuoPgXP9DgeSPU2ewPn0NimVTLp6 +bdV1IIouXprKENAC4nNJTMr7C6YQ1cTOI2N8RSuXAoGAMJCZF0Vi68wc2vTbbxYV +XxMsC2CBzYjZYKkjdzNaG9BGuGyhOPx/hYoCVFDctYLWudVxwH0g+NOhuCTzUG// +wpsaPNeqIRqBGuGp/NLiIMwfk+sK8AS+4RxVOt2nJJaQFE0ho2rxkpJS8pLWHl5v +xeVlBhoNxaWo+IIXROAAvnkCgYEA2Fmh62AE05xXO0e64LiSD8D8m9Quqj7q2lBF +YpHK/4zP6m6u+gRqOUdf5ei6X88/xNEABQTu9UCgAignhkjBwQCKBlFJ0AOpPkhy +Gh2sbgT6kw+VUlibNfgtSuNwxmN+5gRvy+mMcxYqqSXuwfne1BXDu3+78HXk8X+l +exBinGUCgYAqiZZGxJDxGBdeYbFGMEanxKG5c00hfFjTgejTCROQKN+1I+EIOpbT +oFTiTyJkvw/n6sAg7Mz6tgWzZtwWORWW9rflxZKW27qBOs+YNpshVjnpW6iB16/1 +72G3soTzv62xBzwi3KyphPj+yrO6slKqWtXC7Kshtm4ZAYiBMFjltg== +-----END RSA PRIVATE KEY----- diff --git a/offlineauth/test/testdata/keys/root_Key.pem b/offlineauth/test/testdata/keys/root_Key.pem new file mode 100644 index 00000000..4cf45454 --- /dev/null +++ b/offlineauth/test/testdata/keys/root_Key.pem @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +W9oh/H++xEqZ7OtknpmLx7v8+fcH+jmplgDrhi37prBq8RzHjnS7W1Io2XsYW+4e +WPO3LR+hAj/7m5YKu8EI4A== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/testdata/logpk1.pem b/offlineauth/test/testdata/logpk1.pem new file mode 100644 index 00000000..a46139be --- /dev/null +++ b/offlineauth/test/testdata/logpk1.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeAFlWI523VrWfq6Gke2NMaIZ96cW ++Xli8He6nZ0prhzZiFIY2F3WRtb+oAVukWmpthCPKI8oAoxhoeVx7TvLBw== +-----END PUBLIC KEY----- + + diff --git a/offlineauth/test/testdata/mappk1.pem b/offlineauth/test/testdata/mappk1.pem new file mode 100644 index 00000000..495529ce --- /dev/null +++ b/offlineauth/test/testdata/mappk1.pem @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdGRDo0HDCAqH0YtLmAIpl1iTJNY +MwnXCcYWmla6xH6KWdkcxDZQHepVCCQ0df8xoIXHNPzkajJQ7cZO1APuGQ== +-----END PUBLIC KEY----- + diff --git a/offlineauth/test/testdata/rootout/ch_Cert.pem b/offlineauth/test/testdata/rootout/ch_Cert.pem new file mode 100644 index 00000000..12822997 --- /dev/null +++ b/offlineauth/test/testdata/rootout/ch_Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBKzCB3qADAgECAgEAMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMTI5MTUzNDU0WhcNMjIxMTIwMTUzNDU0WjANMQswCQYD +VQQDEwJjaDAqMAUGAytlcAMhAIWZNo5ouIj/VlpdQfa+v1OaZaPGJqxR7Gtz/QYX +zk0+o1AwTjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAW +gBTnvgGG6JMEzvLe0P6DPw7LHdZjnjANBgNVHREEBjAEggJjaDAFBgMrZXADQQCl +Kt9E0PIVJgIvVfAHUGnnDQEs5jpT5VIonxoq1eM42p5ssWo+3OmwAynM01VW1iAA +knaKotcy1r8tA+OEFEYI +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/rootout/ethz.ch_Cert.pem b/offlineauth/test/testdata/rootout/ethz.ch_Cert.pem new file mode 100644 index 00000000..035d5457 --- /dev/null +++ b/offlineauth/test/testdata/rootout/ethz.ch_Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBNTCB6KADAgECAgEAMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMTI5MTUwNTQ4WhcNMjIxMTIwMTUwNTQ4WjASMRAwDgYD +VQQDEwdldGh6LmNoMCowBQYDK2VwAyEA/i3gk00BEwCAwv6Iyo8sIGzBpxV1p1g6 +E9jroIb/E4WjVTBTMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB8GA1Ud +IwQYMBaAFOe+AYbokwTO8t7Q/oM/Dssd1mOeMBIGA1UdEQQLMAmCB2V0aHouY2gw +BQYDK2VwA0EASbyDBotWAmLX8j9DvzmZ+j4ok6Ulxxc8SxzyHAI8CkkQbdUsCHPC +PXD5Nirx1gToWsEJDAFFymKHfz6/KV0VBA== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/rootout/tld1.RHINE_Cert.pem b/offlineauth/test/testdata/rootout/tld1.RHINE_Cert.pem new file mode 100644 index 00000000..ec1c80c1 --- /dev/null +++ b/offlineauth/test/testdata/rootout/tld1.RHINE_Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBQTCB9KADAgECAgEAMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMjAzMTYwMjA2WhcNMjIxMTI0MTYwMjA2WjAbMRkwFwYD +VQQDExBSSElORTp0bGQxLlJISU5FMCowBQYDK2VwAyEASYG79apsin3Ripgkj14o +U54Zma4OJQUJumffjMH6X0ajWDBWMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E +AjAAMB8GA1UdIwQYMBaAFOe+AYbokwTO8t7Q/oM/Dssd1mOeMBUGA1UdEQQOMAyC +CnRsZDEuUkhJTkUwBQYDK2VwA0EAKcu5f6gZtV3VJzMRNw54ILeTM+Fz/p75GU78 +eq0m3E/eRPmDaZBvE1TY/9e2n4DZXgVD3O4TiSH0kk4Tkh7KDg== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/roots/CA2Cert.pem b/offlineauth/test/testdata/roots/CA2Cert.pem new file mode 100644 index 00000000..0ff818dc --- /dev/null +++ b/offlineauth/test/testdata/roots/CA2Cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBMDCB46ADAgECAgEBMAUGAytlcDAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExF +IFJPT1QgQ0EwHhcNMjExMTE1MjAzOTExWhcNMjIxMTA2MjAzOTExWjAgMR4wHAYD +VQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwKjAFBgMrZXADIQBMguNWaDaEfNux +ktPz98+irAJjvhTgNFtYoszyP6HbX6NCMEAwDgYDVR0PAQH/BAQDAgKEMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOe+AYbokwTO8t7Q/oM/Dssd1mOeMAUGAytl +cANBANST2xcaKcjXu8qiRziWWCf3Cmb8jCUIxv7UFmoHHrKN/WoI+1XlvPuzh9nG +fl2GXm7/tBCE1vwdxFofin9HOQk= +-----END CERTIFICATE----- diff --git a/offlineauth/test/testdata/roots/CACert.pem b/offlineauth/test/testdata/roots/CACert.pem new file mode 100644 index 00000000..f22b3eab --- /dev/null +++ b/offlineauth/test/testdata/roots/CACert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDExVSQUlO +UyBFWEFNUExFIFJPT1QgQ0EwHhcNMjExMTA3MjExMTA4WhcNMjIxMDI5MjExMTA4 +WjAgMR4wHAYDVQQDExVSQUlOUyBFWEFNUExFIFJPT1QgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCWf0HP1kGNKQSnhfB74lQqRFH7CogNjDzrfT1P +FJvJfyCTfpsGdEEpUKSIzkhNrxCZqiGdmICnW9rAAMDGAmUw1dkiqBV7gmyzW93N +bk7fTf//a6bCeyb+oDcSpyad8jGo3edcWTaJj2pqJPwxjx+1ONPar1babmlfJ9nI +fEb4jG/nQd6eY8DZxRjRRViPIOeQc1yEpO7FKhQJd6Zj0xy4VBkMZEcZuIwZeHMb +VHBbicQZmmBnjUCv3ArYAQARaDrh9bdwITB0pAuO2P/BS32/Ic78NhrFgaC6elVM +ik0kD8M6gLqsqSlb8BWJVhkIFeTOIvtYur/WwSXFg0J5tQqvAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIChDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTSgQ1hCLQ1 +nHDbzXxaW+k9IxUwDTANBgkqhkiG9w0BAQsFAAOCAQEAG+m8AFQGSBtNwL/1q5cB +GTxBGW2E8sgQ55SGvG//S1FL5CymPsby4xQHf9q/ZHo/R5JTE8z5n0IxWZKRjywy +CfRrqEMY3ftqaYGQ/Qi6CLMhBCB/S623RBl4vG7Sp1jJkURcx3N4l9SWIdRfMoJW +MPXYNhYPiWsPHq7+PrzAfPeuzWyQ7Tbbldz43VIlG8JIo9PnCPxwcHcRN98FVjtw +M7DGhmBXEeddaiHcqcgJwoY92744xCWJLOUz57coVudVkNTQHxNGTommad/xMKz3 +40zH2DoSkObxGfaJblsMvgQa0u2e89GbBShlPK3gXKLIxvIJJCQ+wYTLwdY2XsTW +mw== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testfulldata/ca.cert b/offlineauth/test/testfulldata/ca.cert new file mode 100644 index 00000000..0017c807 --- /dev/null +++ b/offlineauth/test/testfulldata/ca.cert @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBJjCB2aADAgECAgEBMAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDIyMTA5MDI1NVoXDTIzMDIxMjA5MDI1NVowGzEZMBcGA1UEAxMQ +UkhJTkUgRVhBTVBMRSBDQTAqMAUGAytlcAMhAFq9YoSG/zv2npflvTwmog9Ymijs +K0NDTDYFgTbGxyrto0IwQDAOBgNVHQ8BAf8EBAMCAoQwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUXcJH29E2egUuSdhJFoy/kJQDlcwwBQYDK2VwA0EAxB2JHVh+ +N7o3RTBCp7wOWDlGePd0xuhRhU4GEJs4CTxGgLbcyX1iIzF7kJ1qCmp+y180PAJe +xqM22eY3hKQFAQ== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testfulldata/ca.conf b/offlineauth/test/testfulldata/ca.conf new file mode 100644 index 00000000..e6b9b7fb --- /dev/null +++ b/offlineauth/test/testfulldata/ca.conf @@ -0,0 +1,10 @@ +{ + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testfulldata/ca.key", + "CertificatePath": "testfulldata/ca.cert", + "MapServerAddress": "172.18.0.5:8094", + "MapServerPublicKeyPath": "testdata/mappk1.pem", + "MapId": 3213023363744691885, + "ServerAddress": "localhost:10000", + "RootCertsPath": "testfulldata/roots/" +} \ No newline at end of file diff --git a/offlineauth/test/testfulldata/ca.key b/offlineauth/test/testfulldata/ca.key new file mode 100644 index 00000000..28955fdc --- /dev/null +++ b/offlineauth/test/testfulldata/ca.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +pNQ7BgAvsICwu7+Iin8Y88phnZIVbeBZrruqnU5/NwFavWKEhv879p6X5b08JqIP +WJoo7CtDQ0w2BYE2xscq7Q== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/testfulldata/checker.conf b/offlineauth/test/testfulldata/checker.conf new file mode 100644 index 00000000..ee828603 --- /dev/null +++ b/offlineauth/test/testfulldata/checker.conf @@ -0,0 +1,10 @@ +{ + "LogID": 8493809986858120401, + "LogAddress": "172.18.0.3:8090", + "LogPkeyPath": "testdata/logpk1.pem", + "MapID": 3213023363744691885, + "MapAddress": "172.18.0.5:8094", + "MapPkeyPath": "testdata/mappk1.pem", + "RootCertsPath": "testfulldata/roots/", + "ServerAddress": "localhost:10001" +} \ No newline at end of file diff --git a/offlineauth/test/testfulldata/debugcsr.csr b/offlineauth/test/testfulldata/debugcsr.csr new file mode 100644 index 00000000..ec553057 --- /dev/null +++ b/offlineauth/test/testfulldata/debugcsr.csr @@ -0,0 +1,7 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIHAMHQCAQAwGjEYMBYGA1UEAxMPUkhJTkU6Y2gxLnJoaW5lMCowBQYDK2VwAyEA +OXv5c5aprhSVPVeSSI2DWHT10Ss46E//1pWsKSqKVBKgJzAlBgkqhkiG9w0BCQ4x +GDAWMBQGA1UdEQQNMAuCCWNoMS5yaGluZTAFBgMrZXADQQBiiFUXuQIcWgNnl+Dq +bfdUCGr/DjW2+vdExu+1xIXupuPdlQYP1y/mYEUCYmIrDZlAUxXpriBltOXB665Y +/PsE +-----END CERTIFICATE REQUEST----- diff --git a/offlineauth/test/testfulldata/root.conf b/offlineauth/test/testfulldata/root.conf new file mode 100644 index 00000000..8af8dcd6 --- /dev/null +++ b/offlineauth/test/testfulldata/root.conf @@ -0,0 +1,10 @@ +{ + "Zone": "rhine", + "AuthenticationType": "NOAUTH", + "LogCheckerExtAddress": "localhost:10001", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testfulldata/root.key", + "CertificatePath": "", + "CAAddress": "localhost:10000", + "OutputDir": "testfulldata/" +} \ No newline at end of file diff --git a/offlineauth/test/testfulldata/root.key b/offlineauth/test/testfulldata/root.key new file mode 100644 index 00000000..fc7793ed --- /dev/null +++ b/offlineauth/test/testfulldata/root.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- ++UvcceWSr5eLv6V18/KmluAvGbEx/m6vuEkOlwEvOxMjYcvheLELb2SnxoYPjTCk +UN0wV9G3fAqnxSN3ON3Zkw== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/testfulldata/roots/ca.cert b/offlineauth/test/testfulldata/roots/ca.cert new file mode 100644 index 00000000..0017c807 --- /dev/null +++ b/offlineauth/test/testfulldata/roots/ca.cert @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBJjCB2aADAgECAgEBMAUGAytlcDAbMRkwFwYDVQQDExBSSElORSBFWEFNUExF +IENBMB4XDTIyMDIyMTA5MDI1NVoXDTIzMDIxMjA5MDI1NVowGzEZMBcGA1UEAxMQ +UkhJTkUgRVhBTVBMRSBDQTAqMAUGAytlcAMhAFq9YoSG/zv2npflvTwmog9Ymijs +K0NDTDYFgTbGxyrto0IwQDAOBgNVHQ8BAf8EBAMCAoQwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUXcJH29E2egUuSdhJFoy/kJQDlcwwBQYDK2VwA0EAxB2JHVh+ +N7o3RTBCp7wOWDlGePd0xuhRhU4GEJs4CTxGgLbcyX1iIzF7kJ1qCmp+y180PAJe +xqM22eY3hKQFAQ== +-----END CERTIFICATE----- diff --git a/offlineauth/test/testfulldata/tld.conf b/offlineauth/test/testfulldata/tld.conf new file mode 100644 index 00000000..d70989f5 --- /dev/null +++ b/offlineauth/test/testfulldata/tld.conf @@ -0,0 +1,10 @@ +{ + "Zone": "ch1.rhine", + "AuthenticationType": "certificate", + "LogCheckerExtAddress": "localhost:10001", + "PrivateKeyAlgorithm": "Ed25519", + "PrivateKeyPath": "testfulldata/tld.key", + "CertificatePath": "testfulldata/tld.cert", + "CAAddress": "localhost:10000", + "OutputDir": "testfulldata/" +} \ No newline at end of file diff --git a/offlineauth/test/testfulldata/tld.key b/offlineauth/test/testfulldata/tld.key new file mode 100644 index 00000000..67b5243c --- /dev/null +++ b/offlineauth/test/testfulldata/tld.key @@ -0,0 +1,4 @@ +-----BEGIN RAINS Ed25519 PRIVATE KEY----- +j5YdlzpmrSaMGld8dU0yQWiopo7OOc00DMNRvElpk0o5e/lzlqmuFJU9V5JIjYNY +dPXRKzjoT//WlawpKopUEg== +-----END RAINS Ed25519 PRIVATE KEY----- diff --git a/offlineauth/test/trillian/lastIdx b/offlineauth/test/trillian/lastIdx new file mode 100644 index 00000000..62f94575 --- /dev/null +++ b/offlineauth/test/trillian/lastIdx @@ -0,0 +1 @@ +6 \ No newline at end of file diff --git a/test/integration/testdata/messages/messages.txt b/test/integration/testdata/messages/messages.txt index 601f3ee9..de0fc1cc 100644 --- a/test/integration/testdata/messages/messages.txt +++ b/test/integration/testdata/messages/messages.txt @@ -16,6 +16,7 @@ :Q: . www.ethz.ch. [ 9 ] -1 [ ] :Z: ethz.ch. . [ :A: _ftp._tcp [ :srv: ftp.ethz.ch. 20 0 ] + :A: _rhine [ :cert: :rhine: :zoneAuth: :noHash: 308201313081e4a00302010202017b300506032b6570301b31193017060355040313105248494e45204558414d504c45204341301e170d3232303232323230353533385a170d3233303231333230353533385a3000302a300506032b6570032100e399545d248fb3ece0cd822ee3b6222df06fd278308923d9bebef997c9a1afa9a3683066300e0603551d0f0101ff040403020780300c0603551d130101ff04023000301f0603551d230418301680145dc247dbd1367a052e49d849168cbf90940395cc30160603551d110101ff040c300a82086574687a2e63682e300d06042b837409040530030101ff300506032b65700341006746174fee1de919d5a5dfdde0c88bcf1954661f7f6f66189d9f1e18d3ac64e09ce1086eca9fb8aa265730800205806a57c7408a16acd8dbf43dc68576678306 ] :A: www [ :name: a [ :ip6: :ip4: :scion: ] ] :A: www [ :ip6: 2001:db8:85a3::8a2e:370:7334 ] :A: www [ :ip4: 198.175.162.241 ] diff --git a/test/integration/testdata/zonefiles/ethz.ch.txt b/test/integration/testdata/zonefiles/ethz.ch.txt index 23314f1c..27040a85 100644 --- a/test/integration/testdata/zonefiles/ethz.ch.txt +++ b/test/integration/testdata/zonefiles/ethz.ch.txt @@ -4,5 +4,6 @@ :A: www [ :ip4: 198.175.162.241 ] :A: www [ :scion: 2-ff00:0:222,[127.0.0.1] ] :A: www [ :cert: :tls: :endEntity: :sha256: e28b1bd3a73882b198dfe4f0fa954c ] + :A: _rhine [ :cert: :rhine: :zoneAuth: :noHash: 308201313081e4a00302010202017b300506032b6570301b31193017060355040313105248494e45204558414d504c45204341301e170d3232303232323230353533385a170d3233303231333230353533385a3000302a300506032b6570032100e399545d248fb3ece0cd822ee3b6222df06fd278308923d9bebef997c9a1afa9a3683066300e0603551d0f0101ff040403020780300c0603551d130101ff04023000301f0603551d230418301680145dc247dbd1367a052e49d849168cbf90940395cc30160603551d110101ff040c300a82086574687a2e63682e300d06042b837409040530030101ff300506032b65700341006746174fee1de919d5a5dfdde0c88bcf1954661f7f6f66189d9f1e18d3ac64e09ce1086eca9fb8aa265730800205806a57c7408a16acd8dbf43dc68576678306 ] :A: _ftp._tcp [ :srv: ftp.ethz.ch. 20 0 ] ] diff --git a/test/manual/Dockerfile b/test/manual/Dockerfile new file mode 100644 index 00000000..e55ec053 --- /dev/null +++ b/test/manual/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:18.04 + +COPY . / +CMD ["/bin/bash"] + +EXPOSE 5025 \ No newline at end of file diff --git a/test/manual/build/keymanager b/test/manual/build/keymanager new file mode 100644 index 00000000..e69de29b diff --git a/test/manual/build/publisher b/test/manual/build/publisher new file mode 100644 index 00000000..e69de29b diff --git a/test/manual/build/rainsd b/test/manual/build/rainsd new file mode 100644 index 00000000..e69de29b diff --git a/test/manual/build/rdig b/test/manual/build/rdig new file mode 100644 index 00000000..e69de29b diff --git a/test/manual/hostnames.txt b/test/manual/hostnames.txt new file mode 100644 index 00000000..433775a3 --- /dev/null +++ b/test/manual/hostnames.txt @@ -0,0 +1 @@ +:A: scionlab-1301-jitsi [ :scion: 19-ffaa:0:1301,[141.44.17.37] ] diff --git a/test/manual/limit_resources.sh b/test/manual/limit_resources.sh new file mode 100755 index 00000000..1775724c --- /dev/null +++ b/test/manual/limit_resources.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -x + +read -r -a pids <<< $(cat pids.txt) +for pid in "${pids[@]}" +do + cpulimit -p "$pid" -l 10 -b +done + +#ps aux | grep rains +#cpulimit -p 3220 -l 10 -b + + diff --git a/test/manual/pids.txt b/test/manual/pids.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/manual/pids.txt @@ -0,0 +1 @@ + diff --git a/test/manual/run_testservers.sh b/test/manual/run_testservers.sh new file mode 100644 index 00000000..ad194068 --- /dev/null +++ b/test/manual/run_testservers.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -x + +docker build -t rains . +docker run --name rains-resolver -p 127.0.0.1:5025:5025/tcp -d rains sleep infinity + +sleep 2 +Address=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rains-resolver) + +docker exec -it rains-resolver scripts/Server_all.sh tcp ${Address} \ No newline at end of file diff --git a/test/manual/scripts/Server_all.sh b/test/manual/scripts/Server_all.sh index a5319b62..12eb14d1 100755 --- a/test/manual/scripts/Server_all.sh +++ b/test/manual/scripts/Server_all.sh @@ -295,6 +295,8 @@ EOF ZONEFILE=$(zonefile ${ZONE}) gen_ns_config $ZONE 5024 "ethz.ch." gen_pub_config $ZONE 5024 $ZONEFILE "false" + HOSTS="$(cat hostnames.txt)" + echo "$HOSTS" cat > ${ZONEFILE} < pids.txt echo "Log messages so far" tail ${LOGS[*]} cat <