asn1-ut-time-decode.cpp revision 4ee2f4fc8e99dc69ba5d63fd7dd3f52a38d0501e
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * IPRT - ASN.1, UTC TIME and GENERALIZED TIME Types, Decoding.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * Copyright (C) 2006-2014 Oracle Corporation
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * This file is part of VirtualBox Open Source Edition (OSE), as
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * available from http://www.virtualbox.org. This file is free software;
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * you can redistribute it and/or modify it under the terms of the GNU
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * General Public License (GPL) as published by the Free Software
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * Foundation, in version 2 as it comes in the "COPYING" file of the
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * The contents of this file may alternatively be used under the terms
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * of the Common Development and Distribution License Version 1.0
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * VirtualBox OSE distribution, in which case the provisions of the
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * CDDL are applicable instead of those of the GPL.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * You may elect to license modified versions of this file under the
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * terms and conditions of either the GPL or the CDDL or both.
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts/*******************************************************************************
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts* Header Files *
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts*******************************************************************************/
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * Common code for UTCTime and GeneralizedTime converters that normalizes the
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * converted time and checks that the input values doesn't change.
a6bf4d9e39eae70c6b74d0d91d35704662c84ff7Phill Cunnington * @returns IPRT status code.
a6bf4d9e39eae70c6b74d0d91d35704662c84ff7Phill Cunnington * @param pCursor The cursor to use when reporting an error.
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley * @param pThis The time to normalize and check.
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley * @param pszType The type name.
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley * @param pszErrorTag The error tag.
c289b3af72dda73e53e6886c920c198b779ebf37Rich Rileystatic int rtAsn1Time_NormalizeTime(PRTASN1CURSOR pCursor, PRTASN1TIME pThis, const char *pszType, const char *pszErrorTag)
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley && pThis->Time.u8Second < 60) /** @todo what about leap seconds? */
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley if ( TimeCopy.u8MonthDay == pThis->Time.u8MonthDay
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts && TimeCopy.u8Minute == pThis->Time.u8Minute
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts && TimeCopy.u8Second == pThis->Time.u8Second)
a6bf4d9e39eae70c6b74d0d91d35704662c84ff7Phill Cunnington rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_TIME_NORMALIZE_MISMATCH,
c289b3af72dda73e53e6886c920c198b779ebf37Rich Riley "%s: Normalized result not the same as %s: '%.*s'",
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts pszErrorTag, pszType, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_TIME_NORMALIZE_ERROR,
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts "%s: RTTimeNormalize failed on %s: '%.*s'",
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pszErrorTag, pszType, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_TIME_BAD_NORMALIZE_INPUT,
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts "%s: Bad %s values: '%.*s'; mth=%u h=%u min=%u sec=%u",
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pszErrorTag, pszType, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch,
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts pThis->Time.u8Month, pThis->Time.u8Hour, pThis->Time.u8Minute, pThis->Time.u8Second);
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * Converts the UTCTime string into an the RTTIME member of RTASN1TIME.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * @returns IPRT status code.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * @param pCursor The cursor to use when reporting an error.
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * @param pThis The time to parse.
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * @param pszErrorTag The error tag.
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpottsstatic int rtAsn1Time_ConvertUTCTime(PRTASN1CURSOR pCursor, PRTASN1TIME pThis, const char *pszErrorTag)
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * While the current spec says the seconds field is not optional, this
7d395d5d4197d1648464cb3606f69c23f08ffbd6James Phillpotts * restriction was added later on. So, when parsing UTCTime we must deal
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts * with it being absent.
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts bool fHaveSeconds = pThis->Asn1Core.cb == sizeof("YYMMDDHHMMSSZ") - 1;
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts if (fHaveSeconds || pThis->Asn1Core.cb == sizeof("YYMMDDHHMMZ") - 1)
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts const char *pachTime = pThis->Asn1Core.uData.pch;
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts /* Basic encoding validation. */
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts /* Basic conversion. */
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.i32Year = (pachTime[0] - '0') * 10 + (pachTime[1] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.i32Year += pThis->Time.i32Year < 50 ? 2000 : 1900;
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.u8Month = (pachTime[2] - '0') * 10 + (pachTime[3] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.u8MonthDay = (pachTime[4] - '0') * 10 + (pachTime[5] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.u8Hour = (pachTime[6] - '0') * 10 + (pachTime[7] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.u8Minute = (pachTime[8] - '0') * 10 + (pachTime[9] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.u8Second = (pachTime[10] - '0') * 10 + (pachTime[11] - '0');
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pThis->Time.fFlags = RTTIME_FLAGS_TYPE_UTC;
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts /* Check the convered data and normalize the time structure. */
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts rc = rtAsn1Time_NormalizeTime(pCursor, pThis, "UTCTime", pszErrorTag);
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_UTC_TIME_ENCODING, "%s: Bad UTCTime encoding: '%.*s'",
8df974db6a280f05491e26c4f0f59e7568fe5b02James Phillpotts pszErrorTag, pThis->Asn1Core.cb, pachTime);
rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_UTC_TIME_ENCODING, "%s: Bad UTCTime length: %#x",
return rc;
static int rtAsn1Time_ConvertGeneralizedTimeFraction(PRTASN1CURSOR pCursor, const char *pchFraction, uint32_t cchFraction,
pchFraction++;
cchFraction--;
if (!cchFraction)
char chLastDigit;
cchFraction--;
pchFraction++;
if (cchFraction > 0)
return VINF_SUCCESS;
static int rtAsn1Time_ConvertGeneralizedTime(PRTASN1CURSOR pCursor, PRTASN1TIME pThis, const char *pszErrorTag)
int rc;
if (cchLeft > 0)
rc = rtAsn1Time_ConvertGeneralizedTimeFraction(pCursor, pachTime + 14, cchLeft, pThis, pszErrorTag);
return VINF_SUCCESS;
return rc;
RTDECL(int) RTAsn1Time_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1TIME pThis, const char *pszErrorTag)
rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_CURSOR_TAG_MISMATCH, "%s: Not UTCTime nor GeneralizedTime: uTag=%#x",
return rc;
RTDECL(int) RTAsn1UtcTime_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1TIME pThis, const char *pszErrorTag)
return rc;
RTDECL(int) RTAsn1GeneralizedTime_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1TIME pThis, const char *pszErrorTag)
return rc;