Skip to content

Commit

Permalink
Add the ability for html test to accept servers using AIA.
Browse files Browse the repository at this point in the history
Generate an error instead of a warning as these are likely due to issues with a remote server out of your control and will work in most browsers.
  • Loading branch information
tomtom5152 committed Dec 2, 2019
1 parent d9b1c7e commit 7cb03ea
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 2 deletions.
14 changes: 14 additions & 0 deletions htmltest/check-link.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package htmltest

import (
"crypto/x509"
"fmt"
"github.com/wjdp/htmltest/htmldoc"
"github.com/wjdp/htmltest/issues"
"github.com/wjdp/htmltest/output"
"golang.org/x/net/html"
"net/http"
"net/url"
"os"
"path"
"strings"
Expand Down Expand Up @@ -189,6 +191,18 @@ func (hT *HTMLTest) checkExternal(ref *htmldoc.Reference) {
return
}

if certErr, ok := err.(*url.Error).Err.(x509.UnknownAuthorityError); ok {
err = validateCertChain(certErr.Cert)
if err == nil {
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelWarning,
Reference: ref,
Message: "incomplete certificate chain",
})
return
}
}

// Unhandled client error, return generic error
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Expand Down
10 changes: 9 additions & 1 deletion htmltest/check-link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestAnchorExternalInsecureOptionIgnored(t *testing.T) {
hT := tTestFileOpts("fixtures/links/issues/94.html",
map[string]interface{}{
"EnforceHTTPS": true,
"IgnoreURLs": []interface{}{"plantuml.com", "plantuml.net", "forum.plantuml.net"},
"IgnoreURLs": []interface{}{"plantuml.com", "plantuml.net", "forum.plantuml.net"},
})
tExpectIssueCount(t, hT, 0)
}
Expand Down Expand Up @@ -158,6 +158,14 @@ func TestAnchorExternalHTTPSInvalid(t *testing.T) {
tExpectIssueCount(t, hT, 6)
}

func TestAnchorExternalHTTPSMissingChain(t *testing.T) {
// should support https aia
// see issue #130
hT := tTestFileOpts("fixtures/links/https-incomplete-chain.html",
map[string]interface{}{"VCREnable": true})
tExpectIssue(t, hT, "incomplete certificate chain", 1)
}

func TestAnchorExternalHTTPSBadH2(t *testing.T) {
// should connect to servers with bad http/2 support
// See issue #49
Expand Down
12 changes: 12 additions & 0 deletions htmltest/fixtures/links/https-incomplete-chain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>

<body>

<p>Blah blah blah. <a href="https://github.com/octocat/Spoon-Knife/issues">An HTTPS link!</a></p>

<p>
<a href="https://incomplete-chain.badssl.com/">incomplete-chain</a>
</p>
</body>

</html>
73 changes: 72 additions & 1 deletion htmltest/util.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,78 @@
package htmltest

import "net/http"
import (
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)

type CertChainErr struct {
cert *x509.Certificate
chain *x509.CertPool
hintErr error
}

func (e CertChainErr) Error() string {
s := "x509: could not validate certificate chain"
if e.hintErr != nil {
s += fmt.Sprintf(" (possibly because of %q)", e.hintErr)
}
return s
}

func statusCodeValid(code int) bool {
return code == http.StatusPartialContent || code == http.StatusOK
}

func validateCertChain(cert *x509.Certificate) (err error) {
if cert.IssuingCertificateURL == nil {
return CertChainErr{cert: cert}
}

intermediates := x509.NewCertPool()
//roots, err := x509.SystemCertPool()
if err != nil {
return CertChainErr{cert: cert}
}
var certsToFetch []string = cert.IssuingCertificateURL

for i := 0; i < len(certsToFetch); i++ {
url := certsToFetch[i]

resp, err := http.Get(url)
if err != nil {
return CertChainErr{cert: cert, chain: intermediates, hintErr: err}
}

if resp.StatusCode != 200 {
return CertChainErr{cert: cert, chain: intermediates, hintErr: fmt.Errorf("could not fetch certificate at %s (status %d)", url, resp.StatusCode)}
}

certBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return CertChainErr{cert: cert, chain: intermediates, hintErr: err}
}

newCert, err := x509.ParseCertificate(certBytes)
if err != nil {
return CertChainErr{cert: cert, chain: intermediates, hintErr: err}
}

if newCert.CheckSignatureFrom(cert) == nil {
// we have out root
break
}

intermediates.AddCert(newCert)

if newCert.IssuingCertificateURL != nil {
certsToFetch = append(certsToFetch, newCert.IssuingCertificateURL...)
}
}

_, err = cert.Verify(x509.VerifyOptions{
Intermediates: intermediates,
})
return
}

0 comments on commit 7cb03ea

Please sign in to comment.