Пример #1
0
// This function sends a DomainServiceRequest of the type GET_CRL to the domain service,
// and deserializes the response into a pkix.CertificateList containing the revoked certificates.
func RequestCrl(network, addr string) (*pkix.CertificateList, error) {
	reqType := DomainServiceRequest_GET_CRL
	request := &DomainServiceRequest{
		Type: &reqType}

	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	ms := util.NewMessageStream(conn)
	_, err = ms.WriteMessage(request)
	if err != nil {
		return nil, err
	}
	log.Printf("Sent crl request to Domain Service using network %s at address %s.",
		network, addr)
	var response DomainServiceResponse
	err = ms.ReadMessage(&response)
	if err != nil {
		return nil, err
	}
	log.Println("Got response from Domain Service.")
	if errStr := response.GetErrorMessage(); errStr != "" {
		return nil, errors.New(errStr)
	}
	parsedCrl, err := x509.ParseCRL(response.GetCrl())
	return parsedCrl, err
}
Пример #2
0
func FuzzCRL(data []byte) int {
	list, err := x509.ParseCRL(data)
	if err != nil {
		if list != nil {
			panic("list is not nil on error")
		}
		return 0
	}
	return 1
}
Пример #3
0
// fetchCRL fetches and parses a CRL.
func fetchCRL(url string) (*pkix.CertificateList, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	} else if resp.StatusCode >= 300 {
		return nil, errors.New("failed to retrieve CRL")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	resp.Body.Close()

	return x509.ParseCRL(body)
}
Пример #4
0
func (b *backend) pathCRLWrite(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	name := strings.ToLower(d.Get("name").(string))
	if name == "" {
		return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
	}
	crl := d.Get("crl").(string)

	certList, err := x509.ParseCRL([]byte(crl))
	if err != nil {
		return logical.ErrorResponse(fmt.Sprintf("failed to parse CRL: %v", err)), nil
	}
	if certList == nil {
		return logical.ErrorResponse("parsed CRL is nil"), nil
	}

	b.crlUpdateMutex.Lock()
	defer b.crlUpdateMutex.Unlock()

	crlInfo := CRLInfo{
		Serials: map[string]RevokedSerialInfo{},
	}
	for _, revokedCert := range certList.TBSCertList.RevokedCertificates {
		crlInfo.Serials[revokedCert.SerialNumber.String()] = RevokedSerialInfo{}
	}

	entry, err := logical.StorageEntryJSON("crls/"+name, crlInfo)
	if err != nil {
		return nil, err
	}
	if err = req.Storage.Put(entry); err != nil {
		return nil, err
	}

	b.crls[name] = crlInfo

	return nil, nil
}
Пример #5
0
// Generates steps to test out CA configuration -- certificates + CRL expiry,
// and ensure that the certificates are readable after storing them
func generateCATestingSteps(t *testing.T, caCert, caKey, otherCaCert string, intdata, reqdata map[string]interface{}) []logicaltest.TestStep {
	ret := []logicaltest.TestStep{
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data: map[string]interface{}{
				"pem_bundle": caKey + caCert,
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/crl",
			Data: map[string]interface{}{
				"expiry": "16h",
			},
		},

		// Ensure we can fetch it back via unauthenticated means, in various formats
		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "cert/ca",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				if resp.Data["certificate"].(string) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", resp.Data["certificate"].(string), caCert)
				}
				return nil
			},
		},

		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "ca/pem",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				rawBytes := resp.Data["http_raw_body"].([]byte)
				if string(rawBytes) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", string(rawBytes), caCert)
				}
				if resp.Data["http_content_type"].(string) != "application/pkix-cert" {
					return fmt.Errorf("Expected application/pkix-cert as content-type, but got %s", resp.Data["http_content_type"].(string))
				}
				return nil
			},
		},

		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "ca",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				rawBytes := resp.Data["http_raw_body"].([]byte)
				pemBytes := pem.EncodeToMemory(&pem.Block{
					Type:  "CERTIFICATE",
					Bytes: rawBytes,
				})
				if string(pemBytes) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", string(pemBytes), caCert)
				}
				if resp.Data["http_content_type"].(string) != "application/pkix-cert" {
					return fmt.Errorf("Expected application/pkix-cert as content-type, but got %s", resp.Data["http_content_type"].(string))
				}
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.ReadOperation,
			Path:      "config/crl",
			Check: func(resp *logical.Response) error {
				if resp.Data["expiry"].(string) != "16h" {
					return fmt.Errorf("CRL lifetimes do not match (got %s)", resp.Data["expiry"].(string))
				}
				return nil
			},
		},

		// Ensure that both parts of the PEM bundle are required
		// Here, just the cert
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data: map[string]interface{}{
				"pem_bundle": caCert,
			},
			ErrorOk: true,
		},

		// Here, just the key
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data: map[string]interface{}{
				"pem_bundle": caKey,
			},
			ErrorOk: true,
		},

		// Ensure we can fetch it back via unauthenticated means, in various formats
		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "cert/ca",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				if resp.Data["certificate"].(string) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", resp.Data["certificate"].(string), caCert)
				}
				return nil
			},
		},

		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "ca/pem",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				rawBytes := resp.Data["http_raw_body"].([]byte)
				if string(rawBytes) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", string(rawBytes), caCert)
				}
				if resp.Data["http_content_type"].(string) != "application/pkix-cert" {
					return fmt.Errorf("Expected application/pkix-cert as content-type, but got %s", resp.Data["http_content_type"].(string))
				}
				return nil
			},
		},

		logicaltest.TestStep{
			Operation:       logical.ReadOperation,
			Path:            "ca",
			Unauthenticated: true,
			Check: func(resp *logical.Response) error {
				rawBytes := resp.Data["http_raw_body"].([]byte)
				pemBytes := pem.EncodeToMemory(&pem.Block{
					Type:  "CERTIFICATE",
					Bytes: rawBytes,
				})
				if string(pemBytes) != caCert {
					return fmt.Errorf("CA certificate:\n%s\ndoes not match original:\n%s\n", string(pemBytes), caCert)
				}
				if resp.Data["http_content_type"].(string) != "application/pkix-cert" {
					return fmt.Errorf("Expected application/pkix-cert as content-type, but got %s", resp.Data["http_content_type"].(string))
				}
				return nil
			},
		},

		// Test a bunch of generation stuff
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "root/generate/exported",
			Data: map[string]interface{}{
				"common_name": "Root Cert",
				"ttl":         "180h",
			},
			Check: func(resp *logical.Response) error {
				intdata["root"] = resp.Data["certificate"].(string)
				intdata["rootkey"] = resp.Data["private_key"].(string)
				reqdata["pem_bundle"] = intdata["root"].(string) + "\n" + intdata["rootkey"].(string)
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "intermediate/generate/exported",
			Data: map[string]interface{}{
				"common_name": "Intermediate Cert",
			},
			Check: func(resp *logical.Response) error {
				intdata["intermediatecsr"] = resp.Data["csr"].(string)
				intdata["intermediatekey"] = resp.Data["private_key"].(string)
				return nil
			},
		},

		// Re-load the root key in so we can sign it
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "pem_bundle")
				delete(reqdata, "ttl")
				reqdata["csr"] = intdata["intermediatecsr"].(string)
				reqdata["common_name"] = "Intermediate Cert"
				reqdata["ttl"] = "90h"
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "root/sign-intermediate",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "csr")
				delete(reqdata, "common_name")
				delete(reqdata, "ttl")
				intdata["intermediatecert"] = resp.Data["certificate"].(string)
				reqdata["serial_number"] = resp.Data["serial_number"].(string)
				reqdata["certificate"] = resp.Data["certificate"].(string)
				reqdata["pem_bundle"] = intdata["intermediatekey"].(string) + "\n" + resp.Data["certificate"].(string)
				return nil
			},
		},

		// First load in this way to populate the private key
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "pem_bundle")
				return nil
			},
		},

		// Now test setting the intermediate, signed CA cert
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "intermediate/set-signed",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "certificate")
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "revoke",
			Data:      reqdata,
		},

		logicaltest.TestStep{
			Operation: logical.ReadOperation,
			Path:      "crl",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				crlBytes := resp.Data["http_raw_body"].([]byte)
				certList, err := x509.ParseCRL(crlBytes)
				if err != nil {
					t.Fatalf("err: %s", err)
				}
				revokedList := certList.TBSCertList.RevokedCertificates
				if len(revokedList) != 1 {
					t.Fatalf("length of revoked list not 1; %d", len(revokedList))
				}
				revokedString := certutil.GetOctalFormatted(revokedList[0].SerialNumber.Bytes(), ":")
				if revokedString != reqdata["serial_number"].(string) {
					t.Fatalf("got serial %s, expecting %s", revokedString, reqdata["serial_number"].(string))
				}
				delete(reqdata, "serial_number")
				return nil
			},
		},

		// Do it all again, with EC keys and DER format
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "root/generate/exported",
			Data: map[string]interface{}{
				"common_name": "Root Cert",
				"ttl":         "180h",
				"key_type":    "ec",
				"key_bits":    384,
				"format":      "der",
			},
			Check: func(resp *logical.Response) error {
				certBytes, _ := base64.StdEncoding.DecodeString(resp.Data["certificate"].(string))
				certPem := pem.EncodeToMemory(&pem.Block{
					Type:  "CERTIFICATE",
					Bytes: certBytes,
				})
				keyBytes, _ := base64.StdEncoding.DecodeString(resp.Data["private_key"].(string))
				keyPem := pem.EncodeToMemory(&pem.Block{
					Type:  "EC PRIVATE KEY",
					Bytes: keyBytes,
				})
				intdata["root"] = string(certPem)
				intdata["rootkey"] = string(keyPem)
				reqdata["pem_bundle"] = string(certPem) + "\n" + string(keyPem)
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "intermediate/generate/exported",
			Data: map[string]interface{}{
				"format":      "der",
				"key_type":    "ec",
				"key_bits":    384,
				"common_name": "Intermediate Cert",
			},
			Check: func(resp *logical.Response) error {
				csrBytes, _ := base64.StdEncoding.DecodeString(resp.Data["csr"].(string))
				csrPem := pem.EncodeToMemory(&pem.Block{
					Type:  "CERTIFICATE REQUEST",
					Bytes: csrBytes,
				})
				keyBytes, _ := base64.StdEncoding.DecodeString(resp.Data["private_key"].(string))
				keyPem := pem.EncodeToMemory(&pem.Block{
					Type:  "EC PRIVATE KEY",
					Bytes: keyBytes,
				})
				intdata["intermediatecsr"] = string(csrPem)
				intdata["intermediatekey"] = string(keyPem)
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "pem_bundle")
				delete(reqdata, "ttl")
				reqdata["csr"] = intdata["intermediatecsr"].(string)
				reqdata["common_name"] = "Intermediate Cert"
				reqdata["ttl"] = "90h"
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "root/sign-intermediate",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "csr")
				delete(reqdata, "common_name")
				delete(reqdata, "ttl")
				intdata["intermediatecert"] = resp.Data["certificate"].(string)
				reqdata["serial_number"] = resp.Data["serial_number"].(string)
				reqdata["certificate"] = resp.Data["certificate"].(string)
				reqdata["pem_bundle"] = intdata["intermediatekey"].(string) + "\n" + resp.Data["certificate"].(string)
				return nil
			},
		},

		// First load in this way to populate the private key
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "config/ca",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "pem_bundle")
				return nil
			},
		},

		// Now test setting the intermediate, signed CA cert
		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "intermediate/set-signed",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				delete(reqdata, "certificate")
				return nil
			},
		},

		logicaltest.TestStep{
			Operation: logical.WriteOperation,
			Path:      "revoke",
			Data:      reqdata,
		},

		logicaltest.TestStep{
			Operation: logical.ReadOperation,
			Path:      "crl",
			Data:      reqdata,
			Check: func(resp *logical.Response) error {
				crlBytes := resp.Data["http_raw_body"].([]byte)
				certList, err := x509.ParseCRL(crlBytes)
				if err != nil {
					t.Fatalf("err: %s", err)
				}
				revokedList := certList.TBSCertList.RevokedCertificates
				if len(revokedList) != 2 {
					t.Fatalf("length of revoked list not 2; %d", len(revokedList))
				}
				found := false
				for _, revEntry := range revokedList {
					revokedString := certutil.GetOctalFormatted(revEntry.SerialNumber.Bytes(), ":")
					if revokedString == reqdata["serial_number"].(string) {
						found = true

					}
				}
				if !found {
					t.Fatalf("did not find %s in CRL", reqdata["serial_number"].(string))
				}
				delete(reqdata, "serial_number")
				return nil
			},
		},
	}

	return ret
}
Пример #6
0
func main() {
	interPEMPtr := flag.String("inter", "", "a PEM file containing intermediates")
	rootPEMPtr := flag.String("roots", "", "a PEM file containing roots")
	crlPtr := flag.String("crl", "", "a CRL file")

	flag.Parse()

	var rootPool, intermediatePool *x509.CertPool
	var roots, intermediates []*x509.Certificate

	if nil != rootPEMPtr && len(*rootPEMPtr) > 0 {
		rootPool, roots = loadCertPool(*rootPEMPtr)
	}
	if nil != interPEMPtr && len(*interPEMPtr) > 0 {
		intermediatePool, intermediates = loadCertPool(*interPEMPtr)
	}

	var crlData []byte
	if nil != crlPtr && len(*crlPtr) > 0 {
		// Get the crl from the args
		var err error
		crlData, err = ioutil.ReadFile(*crlPtr)
		check(err)
	}

	if len(crlData) > 0 {
		// Maybe it's PEM; try to parse as PEM, if that fails, just use the bytes
		block, _ := pem.Decode(crlData)
		if block != nil {
			crlData = block.Bytes
		}

		crl, err := x509.ParseCRL(crlData)
		if err != nil {
			panic("could not parse CRL")
		}

		// check the CRL is still current
		if crl.HasExpired(time.Now()) {
			fmt.Printf("crl has expired\n")
		}

		var signer *x509.Certificate
		if nil != roots {
			signer = findSigningCert(roots, crl)
			if nil == signer {
				fmt.Printf("Not signed by a root; trying known intermediates\n")
				if nil != intermediates {
					signer = findSigningCert(intermediates, crl)
				}
			}
		}

		if nil != signer {
			fmt.Printf("found signer! %v\n", signer.Subject)
			opts := x509.VerifyOptions{
				Roots:         rootPool,
				Intermediates: intermediatePool,
			}

			if _, err := signer.Verify(opts); err != nil {
				fmt.Println("Warning! Can't verify signer!")
			}
		}

		issuerData, err := asn1.Marshal(crl.TBSCertList.Issuer)
		if nil == err {
			issuerString := base64.StdEncoding.EncodeToString(issuerData)
			fmt.Printf("%v\n", issuerString)
		}
		for revoked := range crl.TBSCertList.RevokedCertificates {
			cert := crl.TBSCertList.RevokedCertificates[revoked]
			fmt.Printf(" %v\n",
				base64.StdEncoding.EncodeToString(cert.SerialNumber.Bytes()))
		}
	}
}
Пример #7
0
func crlRevCheck(certChain []*x509.Certificate) (Warning, error) {
	var warn Warning
	var warnDetails string
	var passedChecks int
	numChecks := len(certChain) - 1 // revocation can't be checked on the root
	// main revocation check loop
	for i := 0; i < numChecks; i++ {
		target := certChain[i]
		issuer := certChain[i+1]
		// get CRL URLs
		urls := target.CRLDistributionPoints
		numURLs := len(urls)
		var triedURLs int
		// url check loop
		for cntr := 0; triedURLs == 0 && cntr < numURLs; cntr++ {
			url := urls[cntr]
			// get CRL
			crl, err := GetCRL(url)
			if err != nil {
				warnDetails = warnDetails + fmt.Sprintf("\n * Failed to get CRL, details: %s", err)
				warn = errors.New(warnDetails)
				break
			}
			// parse CRL
			revCertList, err := x509.ParseCRL(crl)
			if err != nil {
				warnDetails = warnDetails + fmt.Sprintf("\n * Failed to parse CRL, issuer: %s", GetSubjectDN(issuer))
				warn = errors.New(warnDetails)
				break
			}
			// check CRL validity
			if revCertList.HasExpired(time.Now()) {
				warnDetails = warnDetails + fmt.Sprintf("\n * CRL expired, issuer: %s", GetSubjectDN(issuer))
				warn = errors.New(warnDetails)
				break
			}
			// validate CRL signature
			err = issuer.CheckCRLSignature(revCertList)
			if err != nil {
				warnDetails = warnDetails + fmt.Sprintf("\n * CRL signature invalid, issuer: %s", GetSubjectDN(issuer))
				warn = errors.New(warnDetails)
				break
			}
			// check if the cert has been revoked
			err = CheckRevoked(target.SerialNumber, revCertList)
			if err != nil {
				warn = errors.New(warnDetails)
				return warn, err
			}
			triedURLs++
			passedChecks++
		}
	}

	if warn != nil {
		warn = errors.New(warnDetails)
		return warn, nil
	}

	return nil, nil
}