Class: OpenSSL::Timestamp::Response

Inherits:
Object
  • Object
show all
Defined in:
ext/openssl/ossl_ts.c,
ext/openssl/ossl_ts.c

Overview

Immutable and read-only representation of a timestamp response returned from a timestamp server after receiving an associated Request. Allows access to specific information about the response but also allows to verify the Response.

Constant Summary collapse

GRANTED =

Indicates a successful response. Equal to 0.

INT2NUM(TS_STATUS_GRANTED)
GRANTED_WITH_MODS =

Indicates a successful response that probably contains modifications from the initial request. Equal to 1.

INT2NUM(TS_STATUS_GRANTED_WITH_MODS)
REJECTION =

Indicates a failure. No timestamp token was created. Equal to 2.

INT2NUM(TS_STATUS_REJECTION)
WAITING =

Indicates a failure. No timestamp token was created. Equal to 3.

INT2NUM(TS_STATUS_WAITING)
REVOCATION_WARNING =

Indicates a failure. No timestamp token was created. Revocation of a certificate is imminent. Equal to 4.

INT2NUM(TS_STATUS_REVOCATION_WARNING)
REVOCATION_NOTIFICATION =

Indicates a failure. No timestamp token was created. A certificate has been revoked. Equal to 5.

INT2NUM(TS_STATUS_REVOCATION_NOTIFICATION)

Instance Method Summary collapse

Constructor Details

#initialize(der) ⇒ Object

Creates a Response from a File or string parameter, the corresponding File or string must be DER-encoded. Please note that Response is an immutable read-only class. If you’d like to create timestamps please refer to Factory instead.

call-seq:

OpenSSL::Timestamp::Response.new(file)    -> response
OpenSSL::Timestamp::Response.new(string)  -> response


522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
# File 'ext/openssl/ossl_ts.c', line 522

static VALUE
ossl_ts_resp_initialize(VALUE self, VALUE der)
{
    TS_RESP *ts_resp = DATA_PTR(self);
    BIO *in;

    der = ossl_to_der_if_possible(der);
    in  = ossl_obj2bio(&der);
    ts_resp = d2i_TS_RESP_bio(in, &ts_resp);
    BIO_free(in);
    if (!ts_resp) {
        DATA_PTR(self) = NULL;
        ossl_raise(eTimestampError, "Error when decoding the timestamp response");
    }
    DATA_PTR(self) = ts_resp;

    return self;
}

Instance Method Details

#failure_infoObject

In cases no timestamp token has been created, this field contains further info about the reason why response creation failed. The method returns either nil (the request was successful and a timestamp token was created) or one of the following:

  • :BAD_ALG - Indicates that the timestamp server rejects the message imprint algorithm used in the Request

  • :BAD_REQUEST - Indicates that the timestamp server was not able to process the Request properly

  • :BAD_DATA_FORMAT - Indicates that the timestamp server was not able to parse certain data in the Request

  • :TIME_NOT_AVAILABLE - Indicates that the server could not access its time source

  • :UNACCEPTED_POLICY - Indicates that the requested policy identifier is not recognized or supported by the timestamp server

  • :UNACCEPTED_EXTENSIION - Indicates that an extension in the Request is not supported by the timestamp server

  • :ADD_INFO_NOT_AVAILABLE -Indicates that additional information requested is either not understood or currently not available

  • :SYSTEM_FAILURE - Timestamp creation failed due to an internal error that occurred on the timestamp server

call-seq:

response.failure_info -> nil or symbol


588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'ext/openssl/ossl_ts.c', line 588

static VALUE
ossl_ts_resp_get_failure_info(VALUE self)
{
    TS_RESP *resp;
    TS_STATUS_INFO *si;
    const ASN1_BIT_STRING *fi;

    GetTSResponse(self, resp);
    si = TS_RESP_get_status_info(resp);
    fi = TS_STATUS_INFO_get0_failure_info(si);
    if (!fi)
        return Qnil;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_ALG))
        return sBAD_ALG;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_REQUEST))
        return sBAD_REQUEST;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_DATA_FORMAT))
        return sBAD_DATA_FORMAT;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_TIME_NOT_AVAILABLE))
        return sTIME_NOT_AVAILABLE;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_POLICY))
        return sUNACCEPTED_POLICY;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_EXTENSION))
        return sUNACCEPTED_EXTENSION;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_ADD_INFO_NOT_AVAILABLE))
        return sADD_INFO_NOT_AVAILABLE;
    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_SYSTEM_FAILURE))
        return sSYSTEM_FAILURE;

    ossl_raise(eTimestampError, "Unrecognized failure info.");
}

#statusObject

Returns one of GRANTED, GRANTED_WITH_MODS, REJECTION, WAITING, REVOCATION_WARNING or REVOCATION_NOTIFICATION. A timestamp token has been created only in case status is equal to GRANTED or GRANTED_WITH_MODS.

call-seq:

response.status -> BN (never nil)


549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'ext/openssl/ossl_ts.c', line 549

static VALUE
ossl_ts_resp_get_status(VALUE self)
{
    TS_RESP *resp;
    TS_STATUS_INFO *si;
    const ASN1_INTEGER *st;

    GetTSResponse(self, resp);
    si = TS_RESP_get_status_info(resp);
    st = TS_STATUS_INFO_get0_status(si);

    return asn1integer_to_num(st);
}

#status_textObject

In cases of failure this field may contain an array of strings further describing the origin of the failure.

call-seq:

response.status_text -> Array of strings or nil


627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
# File 'ext/openssl/ossl_ts.c', line 627

static VALUE
ossl_ts_resp_get_status_text(VALUE self)
{
    TS_RESP *resp;
    TS_STATUS_INFO *si;
    const STACK_OF(ASN1_UTF8STRING) *text;
    ASN1_UTF8STRING *current;
    int i;
    VALUE ret = rb_ary_new();

    GetTSResponse(self, resp);
    si = TS_RESP_get_status_info(resp);
    if ((text = TS_STATUS_INFO_get0_text(si))) {
        for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {
            current = sk_ASN1_UTF8STRING_value(text, i);
            rb_ary_push(ret, asn1str_to_str(current));
        }
    }

    return ret;
}

#to_derObject

Returns the Response in DER-encoded form.

call-seq:

response.to_der -> string


727
728
729
730
731
732
733
734
# File 'ext/openssl/ossl_ts.c', line 727

static VALUE
ossl_ts_resp_to_der(VALUE self)
{
    TS_RESP *resp;

    GetTSResponse(self, resp);
    return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP);
}

#to_textObject



736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
# File 'ext/openssl/ossl_ts.c', line 736

static VALUE
ossl_ts_resp_to_text(VALUE self)
{
    TS_RESP *resp;
    BIO *out;

    GetTSResponse(self, resp);

    out = BIO_new(BIO_s_mem());
    if (!out) ossl_raise(eTimestampError, NULL);

    if (!TS_RESP_print_bio(out, resp)) {
        BIO_free(out);
        ossl_raise(eTimestampError, NULL);
    }

    return ossl_membio2str(out);
}

#tokenObject

If a timestamp token is present, this returns it in the form of a OpenSSL::PKCS7.

call-seq:

response.token -> nil or OpenSSL::PKCS7


656
657
658
659
660
661
662
663
664
665
666
# File 'ext/openssl/ossl_ts.c', line 656

static VALUE
ossl_ts_resp_get_token(VALUE self)
{
    TS_RESP *resp;
    PKCS7 *p7;

    GetTSResponse(self, resp);
    if (!(p7 = TS_RESP_get_token(resp)))
        return Qnil;
    return ossl_pkcs7_new(p7);
}

#token_infoObject

Get the response’s token info if present.

call-seq:

response.token_info -> nil or OpenSSL::Timestamp::TokenInfo


674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
# File 'ext/openssl/ossl_ts.c', line 674

static VALUE
ossl_ts_resp_get_token_info(VALUE self)
{
    TS_RESP *resp;
    TS_TST_INFO *info, *copy;
    VALUE obj;

    GetTSResponse(self, resp);
    if (!(info = TS_RESP_get_tst_info(resp)))
        return Qnil;

    obj = NewTSTokenInfo(cTimestampTokenInfo);

    if (!(copy = TS_TST_INFO_dup(info)))
        ossl_raise(eTimestampError, NULL);

    SetTSTokenInfo(obj, copy);

    return obj;
}

#tsa_certificateObject

If the Request specified to request the TSA certificate (Request#cert_requested = true), then this field contains the certificate of the timestamp authority.

call-seq:

response.tsa_certificate -> OpenSSL::X509::Certificate or nil


703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'ext/openssl/ossl_ts.c', line 703

static VALUE
ossl_ts_resp_get_tsa_certificate(VALUE self)
{
    TS_RESP *resp;
    PKCS7 *p7;
    PKCS7_SIGNER_INFO *ts_info;
    X509 *cert;

    GetTSResponse(self, resp);
    if (!(p7 = TS_RESP_get_token(resp)))
        return Qnil;
    ts_info = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, 0);
    cert = PKCS7_cert_from_signer_info(p7, ts_info);
    if (!cert)
        return Qnil;
    return ossl_x509_new(cert);
}

#verify(*args) ⇒ Object

Verifies a timestamp token by checking the signature, validating the certificate chain implied by tsa_certificate and by checking conformance to a given Request. Mandatory parameters are the Request associated to this Response, and an OpenSSL::X509::Store of trusted roots.

Intermediate certificates can optionally be supplied for creating the certificate chain. These intermediate certificates must all be instances of OpenSSL::X509::Certificate.

If validation fails, several kinds of exceptions can be raised:

  • TypeError if types don’t fit

  • TimestampError if something is wrong with the timestamp token itself, if it is not conformant to the Request, or if validation of the timestamp certificate chain fails.

call-seq:

response.verify(Request, root_store) -> Response
response.verify(Request, root_store, [intermediate_cert]) -> Response


775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
# File 'ext/openssl/ossl_ts.c', line 775

static VALUE
ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self)
{
    VALUE ts_req, store, intermediates;
    TS_RESP *resp;
    TS_REQ *req;
    X509_STORE *x509st;
    TS_VERIFY_CTX *ctx;
    STACK_OF(X509) *x509inter = NULL;
    PKCS7* p7;
    X509 *cert;
    int status, i, ok;

    rb_scan_args(argc, argv, "21", &ts_req, &store, &intermediates);

    GetTSResponse(self, resp);
    GetTSRequest(ts_req, req);
    x509st = GetX509StorePtr(store);

    if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL))) {
        ossl_raise(eTimestampError, "Error when creating the verification context.");
    }

    if (!NIL_P(intermediates)) {
        x509inter = ossl_protect_x509_ary2sk(intermediates, &status);
        if (status) {
            TS_VERIFY_CTX_free(ctx);
            rb_jump_tag(status);
        }
    } else if (!(x509inter = sk_X509_new_null())) {
        TS_VERIFY_CTX_free(ctx);
        ossl_raise(eTimestampError, "sk_X509_new_null");
    }

    if (!(p7 = TS_RESP_get_token(resp))) {
        TS_VERIFY_CTX_free(ctx);
        sk_X509_pop_free(x509inter, X509_free);
        ossl_raise(eTimestampError, "TS_RESP_get_token");
    }
    for (i=0; i < sk_X509_num(p7->d.sign->cert); i++) {
        cert = sk_X509_value(p7->d.sign->cert, i);
        if (!sk_X509_push(x509inter, cert)) {
            sk_X509_pop_free(x509inter, X509_free);
            TS_VERIFY_CTX_free(ctx);
            ossl_raise(eTimestampError, "sk_X509_push");
        }
        X509_up_ref(cert);
    }

    if (!X509_STORE_up_ref(x509st)) {
        sk_X509_pop_free(x509inter, X509_free);
        TS_VERIFY_CTX_free(ctx);
        ossl_raise(eTimestampError, "X509_STORE_up_ref");
    }

#ifdef HAVE_TS_VERIFY_CTX_SET0_CERTS
    TS_VERIFY_CTX_set0_certs(ctx, x509inter);
    TS_VERIFY_CTX_set0_store(ctx, x509st);
#else
# if OSSL_OPENSSL_PREREQ(3, 0, 0) || OSSL_IS_LIBRESSL
    TS_VERIFY_CTX_set_certs(ctx, x509inter);
# else
    TS_VERIFY_CTS_set_certs(ctx, x509inter);
# endif
    TS_VERIFY_CTX_set_store(ctx, x509st);
#endif
    TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);

    ok = TS_RESP_verify_response(ctx, resp);
    TS_VERIFY_CTX_free(ctx);

    if (!ok)
        ossl_raise(eTimestampError, "TS_RESP_verify_response");

    return self;
}