Exemple #1
0
static AJ_Status DecodeCertificateTime(X509Validity* validity, DER_Element* der)
{
    AJ_Status status;
    DER_Element time;
    uint8_t fmt;

    memset(validity, 0, sizeof (X509Validity));

    if (!der->size) {
        return AJ_ERR_SECURITY;
    }
    fmt = *der->data;
    switch (fmt) {
    case ASN_UTC_TIME:
        status = AJ_ASN1DecodeElement(der, ASN_UTC_TIME, &time);
        if (AJ_OK != status) {
            return status;
        }
        validity->from = AJ_DecodeTime((char*) time.data, "%y%m%d%H%M%SZ");
        break;

    case ASN_GEN_TIME:
        status = AJ_ASN1DecodeElement(der, ASN_GEN_TIME, &time);
        if (AJ_OK != status) {
            return status;
        }
        validity->from = AJ_DecodeTime((char*) time.data, "%Y%m%d%H%M%SZ");
        break;

    default:
        return AJ_ERR_INVALID;
    }

    if (!der->size) {
        return AJ_ERR_SECURITY;
    }
    fmt = *der->data;
    switch (fmt) {
    case ASN_UTC_TIME:
        status = AJ_ASN1DecodeElement(der, ASN_UTC_TIME, &time);
        if (AJ_OK != status) {
            return status;
        }
        validity->to = AJ_DecodeTime((char*) time.data, "%y%m%d%H%M%SZ");
        break;

    case ASN_GEN_TIME:
        status = AJ_ASN1DecodeElement(der, ASN_GEN_TIME, &time);
        if (AJ_OK != status) {
            return status;
        }
        validity->to = AJ_DecodeTime((char*) time.data, "%Y%m%d%H%M%SZ");
        break;

    default:
        return AJ_ERR_INVALID;
    }

    return status;
}
Exemple #2
0
static AJ_Status DecodeCertificateSig(DER_Element* der, ecc_signature* signature)
{
    AJ_Status status;
    DER_Element seq;
    DER_Element int1;
    DER_Element int2;
    uint8_t tags[] = { ASN_INTEGER, ASN_INTEGER };

    status = AJ_ASN1DecodeElement(der, ASN_SEQ, &seq);
    if (AJ_OK != status) {
        return status;
    }
    status = AJ_ASN1DecodeElements(&seq, tags, sizeof (tags), &int1, &int2);
    if (AJ_OK != status) {
        return status;
    }

    /*
     * Skip over unused bits.
     */
    if ((0 < int1.size) && (0 == *int1.data)) {
        int1.data++;
        int1.size--;
    }
    if ((0 < int2.size) && (0 == *int2.data)) {
        int2.data++;
        int2.size--;
    }

    memset(signature, 0, sizeof (ecc_signature));
    AJ_BigvalDecode(int1.data, &signature->r, int1.size);
    AJ_BigvalDecode(int2.data, &signature->s, int2.size);

    return status;
}
Exemple #3
0
AJ_Status AJ_X509DecodeCertificateDER(X509Certificate* certificate, DER_Element* der)
{
    AJ_Status status;
    DER_Element seq;
    DER_Element tbs;
    DER_Element tmp;
    DER_Element oid;
    DER_Element sig;
    const uint8_t tags1[] = { ASN_SEQ };
    const uint8_t tags2[] = { ASN_SEQ, ASN_SEQ, ASN_BITS };

    AJ_InfoPrintf(("AJ_X509DecodeCertificateDER(certificate=%p, der=%p)\n", certificate, der));

    if ((NULL == certificate) || (NULL == der)) {
        return AJ_ERR_INVALID;
    }

    status = AJ_ASN1DecodeElements(der, tags1, sizeof (tags1), &seq);
    if (AJ_OK != status) {
        return status;
    }
    status = AJ_ASN1DecodeElements(&seq, tags2, sizeof (tags2), &tbs, &tmp, &sig);
    if (AJ_OK != status) {
        return status;
    }

    /*
     * The signed TBS includes the sequence and length fields.
     */
    certificate->raw.data = tbs.data - 4;
    certificate->raw.size = tbs.size + 4;

    status = DecodeCertificateTBS(&certificate->tbs, &tbs);
    if (AJ_OK != status) {
        return status;
    }

    /*
     * We only accept ECDSA-SHA256 signed certificates at the moment.
     */
    status = AJ_ASN1DecodeElement(&tmp, ASN_OID, &oid);
    if (AJ_OK != status) {
        return status;
    }
    if (!CompareOID(&oid, OID_SIG_ECDSA_SHA256, sizeof (OID_SIG_ECDSA_SHA256))) {
        return AJ_ERR_INVALID;
    }

    /*
     * Remove the byte specifying unused bits, this should always be zero.
     */
    if ((0 == sig.size) || (0 != *sig.data)) {
        return AJ_ERR_INVALID;
    }
    sig.data++;
    sig.size--;
    status = DecodeCertificateSig(&certificate->signature, &sig);

    return status;
}
Exemple #4
0
static AJ_Status DecodeCertificateName(X509DistinguishedName* dn, DER_Element* der)
{
    AJ_Status status = AJ_OK;
    DER_Element set;
    DER_Element seq;
    DER_Element oid;
    DER_Element tmp;

    memset(dn, 0, sizeof (X509DistinguishedName));

    while ((AJ_OK == status) && (der->size)) {
        status = AJ_ASN1DecodeElement(der, ASN_SET_OF, &set);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElement(&set, ASN_SEQ, &seq);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElement(&seq, ASN_OID, &oid);
        if (AJ_OK != status) {
            return status;
        }
        if (CompareOID(&oid, OID_DN_OU, sizeof (OID_DN_OU))) {
            // Only accept UTF8 strings
            status = AJ_ASN1DecodeElement(&seq, ASN_UTF8, &tmp);
            if (AJ_OK != status) {
                return status;
            }
            dn->ou.data = tmp.data;
            dn->ou.size = tmp.size;
        } else if (CompareOID(&oid, OID_DN_CN, sizeof (OID_DN_CN))) {
            // Only accept UTF8 strings
            status = AJ_ASN1DecodeElement(&seq, ASN_UTF8, &tmp);
            if (AJ_OK != status) {
                return status;
            }
            dn->cn.data = tmp.data;
            dn->cn.size = tmp.size;
        }
    }

    return status;
}
Exemple #5
0
static AJ_Status DecodeCertificateName(DER_Element* der, uint8_t type, AJ_GUID* ou, AJ_GUID* cn)
{
    AJ_Status status = AJ_OK;
    DER_Element set;
    DER_Element seq;
    DER_Element oid;
    DER_Element tmp;

    while ((AJ_OK == status) && (der->size)) {
        status = AJ_ASN1DecodeElement(der, ASN_SET_OF, &set);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElement(&set, ASN_SEQ, &seq);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElement(&seq, ASN_OID, &oid);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElement(&seq, ASN_UTF8, &tmp);
        if (AJ_OK != status) {
            return status;
        }
        if (CompareOID(&oid, OID_DN_OU, sizeof (OID_DN_OU))) {
            status = AJ_GUID_FromString(ou, (const char*) tmp.data);
            if (AJ_OK != status) {
                return status;
            }
        } else if (CompareOID(&oid, OID_DN_CN, sizeof (OID_DN_CN))) {
            status = AJ_GUID_FromString(cn, (const char*) tmp.data);
            if (AJ_OK != status) {
                return status;
            }
        }
    }

    return status;
}
Exemple #6
0
AJ_Status AJ_ASN1DecodeElements(DER_Element* der, uint8_t* tags, size_t len, ...)
{
    AJ_Status status = AJ_OK;
    DER_Element* out;
    va_list argp;
    uint8_t tag;
    uint32_t tmp;

    AJ_InfoPrintf(("AJ_ASN1DecodeElements(der=%p, tags=%p, len=%zu)\n", der, tags, len));

    if ((NULL == der) || (NULL == tags)) {
        return AJ_ERR_INVALID;
    }

    va_start(argp, len);
    while ((AJ_OK == status) && len && (der->size)) {
        tag = *tags++;
        if (ASN_CONTEXT_SPECIFIC == tag) {
            tmp = va_arg(argp, uint32_t);
            tag = (ASN_CONTEXT_SPECIFIC | tmp);
        }
        out = va_arg(argp, DER_Element*);
        len--;
        status = AJ_ASN1DecodeElement(der, tag, out);
    }
    va_end(argp);

    /*
     * Should all be consumed
     */
    if (len || der->size) {
        status = AJ_ERR_INVALID;
    }

    return status;
}
Exemple #7
0
AJ_Status AJ_ASN1DecodeElements(DER_Element* der, const uint8_t* tags, size_t len, ...)
{
    AJ_Status status = AJ_OK;
    DER_Element* out;
    va_list argp;
    uint8_t tag;
    uint32_t tmp;

    AJ_InfoPrintf(("AJ_ASN1DecodeElements(der=%p, tags=%p, len=%zu)\n", der, tags, len));

    if ((NULL == der) || (NULL == tags)) {
        return AJ_ERR_INVALID;
    }

    va_start(argp, len);
    while ((AJ_OK == status) && len && (der->size)) {
        tag = *tags++;
        if (ASN_CONTEXT_SPECIFIC == tag) {
            tmp = va_arg(argp, uint32_t);
            tag = (ASN_CONTEXT_SPECIFIC | tmp);
        }
        out = va_arg(argp, DER_Element*);
        len--;
        status = AJ_ASN1DecodeElement(der, tag, out);
    }
    if (AJ_OK == status) {
        // If unset elements, fail
        if (len) {
            AJ_InfoPrintf(("AJ_ASN1DecodeElements(der=%p, tags=%p, len=%zu): Uninitialized elements\n", der, tags, len));
            status = AJ_ERR_INVALID;
        }
    }
    va_end(argp);

    return status;
}
Exemple #8
0
static AJ_Status DecodeCertificateTBS(X509Certificate* certificate, DER_Element* tbs)
{
    AJ_Status status;
    DER_Element ver;
    DER_Element oid;
    DER_Element iss;
    DER_Element utc;
    DER_Element sub;
    DER_Element pub;
    DER_Element ext;
    DER_Element tmp;
    DER_Element time1;
    DER_Element time2;
    uint8_t tags1[] = { ASN_CONTEXT_SPECIFIC, ASN_INTEGER, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_CONTEXT_SPECIFIC };
    uint8_t tags2[] = { ASN_UTC_TIME, ASN_UTC_TIME };

    status = AJ_ASN1DecodeElements(tbs, tags1, sizeof (tags1), 0, &ver, &certificate->serial, &oid, &iss, &utc, &sub, &pub, 3, &ext);
    if (AJ_OK != status) {
        return status;
    }

    /*
     * We only accept X.509v3 certificates.
     */
    status = AJ_ASN1DecodeElement(&ver, ASN_INTEGER, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    if ((0x1 != tmp.size) || (0x2 != *tmp.data)) {
        return AJ_ERR_INVALID;
    }

    /*
     * We only accept ECDSA-SHA256 signed certificates at the moment.
     */
    status = AJ_ASN1DecodeElement(&oid, ASN_OID, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    if (!CompareOID(&tmp, OID_SIG_ECDSA_SHA256, sizeof (OID_SIG_ECDSA_SHA256))) {
        return AJ_ERR_INVALID;
    }

    status = DecodeCertificateName(&iss, 0, NULL, &certificate->issuer);
    if (AJ_OK != status) {
        return status;
    }
    status = AJ_ASN1DecodeElements(&utc, tags2, sizeof (tags2), &time1, &time2);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificateName(&sub, 0, &certificate->guild, &certificate->subject);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificatePub(&pub, &certificate->keyinfo);
    if (AJ_OK != status) {
        return status;
    }
    memset(certificate->digest, 0, SHA256_DIGEST_LENGTH);
    status = DecodeCertificateExt(certificate, &ext);

    return status;
}
Exemple #9
0
static AJ_Status DecodeCertificateExt(X509Certificate* certificate, DER_Element* der)
{
    AJ_Status status;
    DER_Element tmp;
    DER_Element seq;
    DER_Element oid;
    DER_Element oct;
    uint8_t tags[] = { ASN_OID, ASN_OCTETS };

    certificate->type = UNKNOWN_CERTIFICATE;
    status = AJ_ASN1DecodeElement(der, ASN_SEQ, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    der->size = tmp.size;
    der->data = tmp.data;
    while ((AJ_OK == status) && (der->size)) {
        status = AJ_ASN1DecodeElement(der, ASN_SEQ, &seq);
        if (AJ_OK != status) {
            return status;
        }
        status = AJ_ASN1DecodeElements(&seq, tags, sizeof (tags), &oid, &oct);
        if (AJ_OK != status) {
            return status;
        }
        if (CompareOID(&oid, OID_BASIC_CONSTRAINTS, sizeof (OID_BASIC_CONSTRAINTS))) {
            status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq);
            if (AJ_OK != status) {
                return status;
            }
            status = AJ_ASN1DecodeElement(&seq, ASN_BOOLEAN, &tmp);
            if (AJ_OK != status) {
                return status;
            }
        } else if (CompareOID(&oid, OID_CUSTOM_CERT_TYPE, sizeof (OID_CUSTOM_CERT_TYPE))) {
            status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq);
            if (AJ_OK != status) {
                return status;
            }
            status = AJ_ASN1DecodeElement(&seq, ASN_INTEGER, &tmp);
            if (AJ_OK != status) {
                return status;
            }
            if (sizeof (uint32_t) < tmp.size) {
                return AJ_ERR_INVALID;
            }
            certificate->type = 0;
            while (tmp.size--) {
                certificate->type <<= 8;
                certificate->type  |= *tmp.data++;
            }
        } else if (CompareOID(&oid, OID_SUB_ALTNAME, sizeof (OID_SUB_ALTNAME))) {
            certificate->alias.size = oct.size;
            certificate->alias.data = oct.data;
        } else if (CompareOID(&oid, OID_CUSTOM_DIGEST, sizeof (OID_CUSTOM_DIGEST))) {
            status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq);
            if (AJ_OK != status) {
                return status;
            }
            status = AJ_ASN1DecodeElements(&seq, tags, sizeof (tags), &oid, &oct);
            if (AJ_OK != status) {
                return status;
            }
            if (!CompareOID(&oid, OID_DIG_SHA256, sizeof (OID_DIG_SHA256))) {
                return AJ_ERR_INVALID;
            }
            if (SHA256_DIGEST_LENGTH != oct.size) {
                return AJ_ERR_INVALID;
            }
            memcpy(certificate->digest, oct.data, SHA256_DIGEST_LENGTH);
        } else {
            // Ignore extensions we don't know
            AJ_DumpBytes("UNKNOWN", oid.data, oid.size);
            AJ_DumpBytes("UNKNOWN", oct.data, oct.size);
        }
    }

    return status;
}
Exemple #10
0
static AJ_Status DecodeCertificateTBS(X509TbsCertificate* tbs, DER_Element* der)
{
    AJ_Status status;
    DER_Element ver;
    DER_Element oid;
    DER_Element iss;
    DER_Element utc;
    DER_Element sub;
    DER_Element pub;
    DER_Element ext;
    DER_Element tmp;
    const uint8_t tags[] = { ASN_CONTEXT_SPECIFIC, ASN_INTEGER, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_SEQ, ASN_CONTEXT_SPECIFIC };

    memset(tbs, 0, sizeof (X509TbsCertificate));

    status = AJ_ASN1DecodeElements(der, tags, sizeof (tags), 0, &ver, &tbs->serial, &oid, &iss, &utc, &sub, &pub, 3, &ext);
    if (AJ_OK != status) {
        return status;
    }

    /*
     * We only accept X.509v3 certificates.
     */
    status = AJ_ASN1DecodeElement(&ver, ASN_INTEGER, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    if ((0x1 != tmp.size) || (0x2 != *tmp.data)) {
        return AJ_ERR_INVALID;
    }

    /*
     * We only accept ECDSA-SHA256 signed certificates at the moment.
     */
    status = AJ_ASN1DecodeElement(&oid, ASN_OID, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    if (!CompareOID(&tmp, OID_SIG_ECDSA_SHA256, sizeof (OID_SIG_ECDSA_SHA256))) {
        return AJ_ERR_INVALID;
    }

    status = DecodeCertificateName(&tbs->issuer, &iss);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificateTime(&tbs->validity, &utc);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificateName(&tbs->subject, &sub);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificatePub(&tbs->publickey, &pub);
    if (AJ_OK != status) {
        return status;
    }
    status = DecodeCertificateExt(&tbs->extensions, &ext);
    if (AJ_OK != status) {
        return status;
    }

    return status;
}
Exemple #11
0
static AJ_Status DecodeCertificateExt(X509Extensions* extensions, DER_Element* der)
{
    AJ_Status status;
    DER_Element tmp;
    DER_Element seq;
    DER_Element savedSeq;
    DER_Element boolVal;
    DER_Element intVal;
    DER_Element oid;
    DER_Element oct;
    const uint8_t tags[] = { ASN_OID, ASN_OCTETS };
    const uint8_t tagsWithCritical[] = { ASN_OID, ASN_BOOLEAN, ASN_OCTETS };
    const uint8_t tagsCAPathLen[] = { ASN_BOOLEAN, ASN_INTEGER };

    memset(extensions, 0, sizeof (X509Extensions));

    status = AJ_ASN1DecodeElement(der, ASN_SEQ, &tmp);
    if (AJ_OK != status) {
        return status;
    }
    der->size = tmp.size;
    der->data = tmp.data;
    while ((AJ_OK == status) && (der->size)) {
        status = AJ_ASN1DecodeElement(der, ASN_SEQ, &seq);
        if (AJ_OK != status) {
            return status;
        }
        savedSeq.size = seq.size;
        savedSeq.data = seq.data;

        status = AJ_ASN1DecodeElements(&seq, tagsWithCritical, sizeof (tagsWithCritical), &oid, &boolVal, &oct);
        if (AJ_OK != status) {
            status = AJ_ASN1DecodeElements(&savedSeq, tags, sizeof (tags), &oid, &oct);
            if (AJ_OK != status) {
                return status;
            }
        }
        if (CompareOID(&oid, OID_BASIC_CONSTRAINTS, sizeof (OID_BASIC_CONSTRAINTS))) {
            status = AJ_ASN1DecodeElement(&oct, ASN_SEQ, &seq);
            if (AJ_OK != status) {
                return status;
            }
            // Explicit boolean (non-empty sequence)
            if (seq.size) {
                savedSeq.size = seq.size;
                savedSeq.data = seq.data;
                status = AJ_ASN1DecodeElements(&seq, tagsCAPathLen, sizeof (tagsCAPathLen), &tmp, &intVal);
                if (AJ_OK != status) {
                    status = AJ_ASN1DecodeElement(&savedSeq, ASN_BOOLEAN, &tmp);
                    if (AJ_OK != status) {
                        return status;
                    }
                }
                if (tmp.size) {
                    extensions->ca = *tmp.data;
                }
            }
        }
    }

    return status;
}