提交 445375dc 编写于 作者: Y YiLin.Li 提交者: jia zhang

rune/libenclave/attestation: Add ias.GetVerifiedReport service

Signed-off-by: NYilin Li <YiLin.Li@linux.alibaba.com>
上级 b27065b4
package attestation // import "github.com/opencontainers/runc/libenclave/attestation"
func (svc *Service) GetVerifiedReport(q []byte) (*Status, map[string]string, error) {
return svc.Attester.GetVerifiedReport(q)
}
...@@ -17,6 +17,7 @@ type Attester interface { ...@@ -17,6 +17,7 @@ type Attester interface {
PrepareChallenge() (*pb.AttestChallenge, error) PrepareChallenge() (*pb.AttestChallenge, error)
HandleChallengeResponse(r *pb.AttestResponse) (*Quote, error) HandleChallengeResponse(r *pb.AttestResponse) (*Quote, error)
Check([]byte) error Check([]byte) error
GetVerifiedReport([]byte) (*Status, map[string]string, error)
Verify([]byte) *Status Verify([]byte) *Status
ShowStatus(status *Status) ShowStatus(status *Status)
} }
......
...@@ -187,7 +187,7 @@ func (ias *iasService) Check(q []byte) error { ...@@ -187,7 +187,7 @@ func (ias *iasService) Check(q []byte) error {
return nil return nil
} }
func (ias *iasService) Verify(quote []byte) *attest.Status { func (ias *iasService) getIasReport(quote []byte) (*attest.Status, map[string]string, error) {
nonce := strconv.FormatUint(rand.Uint64(), 16) + strconv.FormatUint(rand.Uint64(), 16) nonce := strconv.FormatUint(rand.Uint64(), 16) + strconv.FormatUint(rand.Uint64(), 16)
p := &evidencePayload{ p := &evidencePayload{
IsvEnclaveQuote: base64.StdEncoding.EncodeToString(quote), IsvEnclaveQuote: base64.StdEncoding.EncodeToString(quote),
...@@ -204,20 +204,36 @@ func (ias *iasService) Verify(quote []byte) *attest.Status { ...@@ -204,20 +204,36 @@ func (ias *iasService) Verify(quote []byte) *attest.Status {
var err error var err error
if resp, err = ias.reportAttestationEvidence(p); err != nil { if resp, err = ias.reportAttestationEvidence(p); err != nil {
status.ErrorMessage = fmt.Sprintf("%s", err) status.ErrorMessage = fmt.Sprintf("%s", err)
return status return status, nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
var reportStatus *reportStatus var reportStatus *reportStatus
if reportStatus, err = checkVerificationReport(resp, quote, nonce); err != nil { reportStatus, rawReport, err := checkVerificationReport(resp, quote, nonce)
if err != nil {
status.ErrorMessage = fmt.Sprintf("%s", err) status.ErrorMessage = fmt.Sprintf("%s", err)
return status return status, nil, err
} }
iasReport := formatIasReport(resp, rawReport)
status.SpecificStatus = reportStatus status.SpecificStatus = reportStatus
return status, iasReport, nil
}
func (ias *iasService) Verify(quote []byte) *attest.Status {
status, _, err := ias.getIasReport(quote)
if err != nil {
return nil
}
return status return status
} }
func (ias *iasService) GetVerifiedReport(quote []byte) (*attest.Status, map[string]string, error) {
return ias.getIasReport(quote)
}
func (ias *iasService) ShowStatus(status *attest.Status) { func (ias *iasService) ShowStatus(status *attest.Status) {
s, ok := status.SpecificStatus.(*reportStatus) s, ok := status.SpecificStatus.(*reportStatus)
if ok { if ok {
...@@ -279,7 +295,21 @@ func (ias *iasService) reportAttestationEvidence(p *evidencePayload) (*http.Resp ...@@ -279,7 +295,21 @@ func (ias *iasService) reportAttestationEvidence(p *evidencePayload) (*http.Resp
return resp, nil return resp, nil
} }
func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*reportStatus, error) { func formatIasReport(resp *http.Response, rawReport string) map[string]string {
iasReport := make(map[string]string)
iasReport["Body"] = rawReport
iasReport["StatusCode"] = strconv.FormatUint(uint64(resp.StatusCode), 10)
iasReport["Request-ID"] = resp.Header.Get("Request-ID")
iasReport["X-Iasreport-Signature"] = resp.Header.Get("X-Iasreport-Signature")
iasReport["X-Iasreport-Signing-Certificate"] = resp.Header.Get("X-Iasreport-Signing-Certificate")
iasReport["ContentLength"] = strconv.FormatUint(uint64(resp.ContentLength), 10)
iasReport["Content-Type"] = resp.Header.Get("Content-Type")
return iasReport
}
func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*reportStatus, string, error) {
status := &reportStatus{ status := &reportStatus{
requestId: "", requestId: "",
reportId: "", reportId: "",
...@@ -301,43 +331,43 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -301,43 +331,43 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
default: default:
} }
return status, fmt.Errorf("%s: %s", resp.Status, errMsg) return status, "", fmt.Errorf("%s: %s", resp.Status, errMsg)
} }
reqId := resp.Header.Get("Request-ID") reqId := resp.Header.Get("Request-ID")
if reqId == "" { if reqId == "" {
return status, fmt.Errorf("No Request-ID in response header") return status, "", fmt.Errorf("No Request-ID in response header")
} }
status.requestId = reqId status.requestId = reqId
if resp.Header.Get("X-Iasreport-Signature") == "" { if resp.Header.Get("X-Iasreport-Signature") == "" {
return status, fmt.Errorf("No X-Iasreport-Signature in response header") return status, "", fmt.Errorf("No X-Iasreport-Signature in response header")
} }
if resp.Header.Get("X-Iasreport-Signing-Certificate") == "" { if resp.Header.Get("X-Iasreport-Signing-Certificate") == "" {
return status, fmt.Errorf("No X-Iasreport-Signing-Certificate in response header") return status, "", fmt.Errorf("No X-Iasreport-Signing-Certificate in response header")
} }
if resp.ContentLength == -1 { if resp.ContentLength == -1 {
return status, fmt.Errorf("Unknown length of response body") return status, "", fmt.Errorf("Unknown length of response body")
} }
if resp.Header.Get("Content-Type") != "application/json" { if resp.Header.Get("Content-Type") != "application/json" {
return status, fmt.Errorf("Invalid content type (%s) in response", return status, "", fmt.Errorf("Invalid content type (%s) in response",
resp.Header.Get("Content-Type")) resp.Header.Get("Content-Type"))
} }
var err error var err error
rawReport := make([]byte, resp.ContentLength) rawReport := make([]byte, resp.ContentLength)
if _, err = io.ReadFull(resp.Body, rawReport); err != nil { if _, err = io.ReadFull(resp.Body, rawReport); err != nil {
return status, fmt.Errorf("Failed to read reponse body (%d-byte): %s", return status, "", fmt.Errorf("Failed to read reponse body (%d-byte): %s",
resp.ContentLength, err) resp.ContentLength, err)
} }
var report verificationReport var report verificationReport
if err = json.Unmarshal(rawReport, &report); err != nil { if err = json.Unmarshal(rawReport, &report); err != nil {
return status, fmt.Errorf("Failed to unmarshal attestation verification report: %s: %s", return status, "", fmt.Errorf("Failed to unmarshal attestation verification report: %s: %s",
rawReport, err) rawReport, err)
} }
...@@ -346,19 +376,19 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -346,19 +376,19 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
status.quoteStatus = report.IsvEnclaveQuoteStatus status.quoteStatus = report.IsvEnclaveQuoteStatus
if report.Version != (uint32)(apiVersion) { if report.Version != (uint32)(apiVersion) {
return status, fmt.Errorf("Unsupported attestation API version %d in attesation verification report", return status, "", fmt.Errorf("Unsupported attestation API version %d in attesation verification report",
report.Version) report.Version)
} }
if report.Nonce != nonce { if report.Nonce != nonce {
return status, fmt.Errorf("Invalid nonce in attestation verification report: %s", return status, "", fmt.Errorf("Invalid nonce in attestation verification report: %s",
report.Nonce) report.Nonce)
} }
if report.Id == "" || report.Timestamp == "" || if report.Id == "" || report.Timestamp == "" ||
report.IsvEnclaveQuoteStatus == "" || report.IsvEnclaveQuoteStatus == "" ||
report.IsvEnclaveQuoteBody == "" { report.IsvEnclaveQuoteBody == "" {
return status, fmt.Errorf("Required fields in attestation verification report is not present: %s", return status, "", fmt.Errorf("Required fields in attestation verification report is not present: %s",
string(rawReport)) string(rawReport))
} }
...@@ -366,27 +396,27 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -366,27 +396,27 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
report.IsvEnclaveQuoteStatus == "CONFIGURATION_NEEDED" { report.IsvEnclaveQuoteStatus == "CONFIGURATION_NEEDED" {
if report.Version == apiV3 { if report.Version == apiV3 {
if resp.Header.Get("Advisory-Ids") == "" || resp.Header.Get("Advisory-Url") == "" { if resp.Header.Get("Advisory-Ids") == "" || resp.Header.Get("Advisory-Url") == "" {
return status, fmt.Errorf("Advisory-Ids or Advisory-Url is not present in response header") return status, "", fmt.Errorf("Advisory-Ids or Advisory-Url is not present in response header")
} }
} else if report.Version == apiV4 && (report.AdvisoryIds == "" || report.AdvisoryUrl == nil) { } else if report.Version == apiV4 && (report.AdvisoryIds == "" || report.AdvisoryUrl == nil) {
return status, fmt.Errorf("Advisory-Ids or Advisory-Url is not present in attestation verification report") return status, "", fmt.Errorf("Advisory-Ids or Advisory-Url is not present in attestation verification report")
} }
} }
var quoteBody []byte var quoteBody []byte
if quoteBody, err = base64.StdEncoding.DecodeString(report.IsvEnclaveQuoteBody); err != nil { if quoteBody, err = base64.StdEncoding.DecodeString(report.IsvEnclaveQuoteBody); err != nil {
return status, fmt.Errorf("Invalid isvEnclaveQuoteBody: %s", return status, "", fmt.Errorf("Invalid isvEnclaveQuoteBody: %s",
report.IsvEnclaveQuoteBody) report.IsvEnclaveQuoteBody)
} }
if len(quoteBody) != intelsgx.QuoteBodyLength+intelsgx.ReportBodyLength { if len(quoteBody) != intelsgx.QuoteBodyLength+intelsgx.ReportBodyLength {
return status, fmt.Errorf("Invalid length of isvEnclaveQuoteBody: %d-byte", return status, "", fmt.Errorf("Invalid length of isvEnclaveQuoteBody: %d-byte",
len(quoteBody)) len(quoteBody))
} }
for i, v := range quoteBody { for i, v := range quoteBody {
if v != quote[i] { if v != quote[i] {
return status, fmt.Errorf("Unexpected isvEnclaveQuoteBody: %s", return status, "", fmt.Errorf("Unexpected isvEnclaveQuoteBody: %s",
report.IsvEnclaveQuoteBody) report.IsvEnclaveQuoteBody)
} }
} }
...@@ -394,14 +424,14 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -394,14 +424,14 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
var sig []byte var sig []byte
if sig, err = base64.StdEncoding.DecodeString( if sig, err = base64.StdEncoding.DecodeString(
resp.Header.Get("X-Iasreport-Signature")); err != nil { resp.Header.Get("X-Iasreport-Signature")); err != nil {
return status, fmt.Errorf("Invalid X-Iasreport-Signature in response header: %s", return status, "", fmt.Errorf("Invalid X-Iasreport-Signature in response header: %s",
resp.Header.Get("X-Iasreport-Signature")) resp.Header.Get("X-Iasreport-Signature"))
} }
var pemCerts string var pemCerts string
if pemCerts, err = url.QueryUnescape( if pemCerts, err = url.QueryUnescape(
resp.Header.Get("X-Iasreport-Signing-Certificate")); err != nil { resp.Header.Get("X-Iasreport-Signing-Certificate")); err != nil {
return status, fmt.Errorf("Failed to unescape X-Iasreport-Signing-Certificate in response header: %s: %s", return status, "", fmt.Errorf("Failed to unescape X-Iasreport-Signing-Certificate in response header: %s: %s",
resp.Header.Get("X-Iasreport-Signing-Certificate"), err) resp.Header.Get("X-Iasreport-Signing-Certificate"), err)
} }
...@@ -413,7 +443,7 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -413,7 +443,7 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
var b *pem.Block var b *pem.Block
if b, rawPemCerts = pem.Decode(rawPemCerts); err != nil { if b, rawPemCerts = pem.Decode(rawPemCerts); err != nil {
return status, fmt.Errorf("Failed to convert PEM certificate to DER format: %s: %s", return status, "", fmt.Errorf("Failed to convert PEM certificate to DER format: %s: %s",
pemCerts, err) pemCerts, err)
} }
...@@ -422,7 +452,7 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -422,7 +452,7 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
} }
if b.Type != "CERTIFICATE" { if b.Type != "CERTIFICATE" {
return status, fmt.Errorf("Returned content is not PEM certificate: %s", return status, "", fmt.Errorf("Returned content is not PEM certificate: %s",
b.Type) b.Type)
} }
...@@ -431,25 +461,25 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (* ...@@ -431,25 +461,25 @@ func checkVerificationReport(resp *http.Response, quote []byte, nonce string) (*
var x509Certs []*x509.Certificate var x509Certs []*x509.Certificate
if x509Certs, err = x509.ParseCertificates(derCerts); err != nil { if x509Certs, err = x509.ParseCertificates(derCerts); err != nil {
return status, fmt.Errorf("Failed to parse certificates: %s", err) return status, "", fmt.Errorf("Failed to parse certificates: %s", err)
} }
cert := x509Certs[0] cert := x509Certs[0]
if err = cert.CheckSignature(x509.SHA256WithRSA, rawReport, sig); err != nil { if err = cert.CheckSignature(x509.SHA256WithRSA, rawReport, sig); err != nil {
return status, fmt.Errorf("Failed to verify the attestation verification report: %s", return status, "", fmt.Errorf("Failed to verify the attestation verification report: %s",
err) err)
} }
for _, parentCert := range x509Certs[1:] { for _, parentCert := range x509Certs[1:] {
if err = cert.CheckSignatureFrom(parentCert); err != nil { if err = cert.CheckSignatureFrom(parentCert); err != nil {
return status, fmt.Errorf("Failed to verify the certificate (%s) with parent certificate (%s): %s", return status, "", fmt.Errorf("Failed to verify the certificate (%s) with parent certificate (%s): %s",
cert.Subject.String(), parentCert.Subject.String(), err) cert.Subject.String(), parentCert.Subject.String(), err)
} }
cert = parentCert cert = parentCert
} }
return status, nil return status, string(rawReport), nil
} }
func init() { func init() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册