private static byte[] MakeTicketIntoBinaryBlob(FormsAuthenticationTicket ticket) { if (((ticket.Name == null) || (ticket.UserData == null)) || (ticket.CookiePath == null)) { return(null); } if (!AppSettings.UseLegacyFormsAuthenticationTicketCompatibility) { return(FormsAuthenticationTicketSerializer.Serialize(ticket)); } byte[] dst = new byte[0x1000]; byte[] pBytes = new byte[4]; long[] pDates = new long[2]; if (((_Protection != FormsProtectionEnum.All) && (_Protection != FormsProtectionEnum.Encryption)) || (MachineKeySection.CompatMode == MachineKeyCompatibilityMode.Framework20SP1)) { byte[] data = new byte[8]; new RNGCryptoServiceProvider().GetBytes(data); Buffer.BlockCopy(data, 0, dst, 0, 8); } pBytes[0] = (byte)ticket.Version; pBytes[1] = ticket.IsPersistent ? ((byte)1) : ((byte)0); pDates[0] = ticket.IssueDate.ToFileTime(); pDates[1] = ticket.Expiration.ToFileTime(); int count = System.Web.UnsafeNativeMethods.CookieAuthConstructTicket(dst, dst.Length, ticket.Name, ticket.UserData, ticket.CookiePath, pBytes, pDates); if (count < 0) { return(null); } byte[] buffer4 = new byte[count]; Buffer.BlockCopy(dst, 0, buffer4, 0, count); return(buffer4); }
///////////////////////////////////////////////////////////////////////////// private static byte[] MakeTicketIntoBinaryBlob(FormsAuthenticationTicket ticket) { // None of the modes (Framework20 / Framework40 / beyond) support null values for these fields; // they always eventually just returned a null value. if (ticket.Name == null || ticket.UserData == null || ticket.CookiePath == null) { return(null); } // ** MSRC 11838 ** // Framework20 / Framework40 ticket generation modes are insecure. We should use a // secure serialization mode by default. if (!AppSettings.UseLegacyFormsAuthenticationTicketCompatibility) { return(FormsAuthenticationTicketSerializer.Serialize(ticket)); } // ** MSRC 11838 ** // If we have reached this point of execution, the developer has explicitly elected // to continue using the insecure code path instead of the secure one. We removed // the Framework40 serialization mode, so everybody using the legacy code path is // forced to Framework20. byte [] bData = new byte[4096]; byte [] pBin = new byte[4]; long [] pDates = new long[2]; byte [] pNull = { 0, 0, 0 }; // DevDiv Bugs 137864: 8 bytes may not be enough random bits as the length should be equal to the // key size. In CompatMode > Framework20SP1, use the IVType.Random feature instead of these 8 bytes, // but still include empty 8 bytes for compat with webengine.dll, where CookieAuthConstructTicket is. // Note that even in CompatMode = Framework20SP2 we fill 8 bytes with random data if the ticket // is not going to be encrypted. bool willEncrypt = (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Encryption); bool legacyPadding = !willEncrypt || (MachineKeySection.CompatMode == MachineKeyCompatibilityMode.Framework20SP1); if (legacyPadding) { // Fill the first 8 bytes of the blob with random bits byte[] bRandom = new byte[8]; RNGCryptoServiceProvider randgen = new RNGCryptoServiceProvider(); randgen.GetBytes(bRandom); Buffer.BlockCopy(bRandom, 0, bData, 0, 8); } else { // use blank 8 bytes for compatibility with CookieAuthConstructTicket (do nothing) } pBin[0] = (byte)ticket.Version; pBin[1] = (byte)(ticket.IsPersistent ? 1 : 0); pDates[0] = ticket.IssueDate.ToFileTime(); pDates[1] = ticket.Expiration.ToFileTime(); int iRet = UnsafeNativeMethods.CookieAuthConstructTicket( bData, bData.Length, ticket.Name, ticket.UserData, ticket.CookiePath, pBin, pDates); if (iRet < 0) { return(null); } byte[] ciphertext = new byte[iRet]; Buffer.BlockCopy(bData, 0, ciphertext, 0, iRet); return(ciphertext); }
///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Decrypt and get the auth ticket /// <devdoc> /// <para>Given an encrypted authenitcation ticket as /// obtained from an HTTP cookie, this method returns an instance of a /// FormsAuthenticationTicket class.</para> /// </devdoc> public static FormsAuthenticationTicket Decrypt(string encryptedTicket) { if (String.IsNullOrEmpty(encryptedTicket) || encryptedTicket.Length > MAX_TICKET_LENGTH) { throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "encryptedTicket")); } Initialize(); byte[] bBlob = null; if ((encryptedTicket.Length % 2) == 0) // Could be a hex string { try { bBlob = CryptoUtil.HexToBinary(encryptedTicket); } catch { } } if (bBlob == null) { bBlob = HttpServerUtility.UrlTokenDecode(encryptedTicket); } if (bBlob == null || bBlob.Length < 1) { throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "encryptedTicket")); } int ticketLength; if (AspNetCryptoServiceProvider.Instance.IsDefaultProvider) { // If new crypto routines are enabled, call them instead. ICryptoService cryptoService = AspNetCryptoServiceProvider.Instance.GetCryptoService(Purpose.FormsAuthentication_Ticket); byte[] unprotectedData = cryptoService.Unprotect(bBlob); ticketLength = unprotectedData.Length; bBlob = unprotectedData; } else { #pragma warning disable 618 // calling obsolete methods // Otherwise call into MachineKeySection routines. if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Encryption) { // DevDiv Bugs 137864: Include a random IV if under the right compat mode // for improved encryption semantics bBlob = MachineKeySection.EncryptOrDecryptData(false, bBlob, null, 0, bBlob.Length, false, false, IVType.Random); if (bBlob == null) { return(null); } } ticketLength = bBlob.Length; if (_Protection == FormsProtectionEnum.All || _Protection == FormsProtectionEnum.Validation) { if (!MachineKeySection.VerifyHashedData(bBlob)) { return(null); } ticketLength -= MachineKeySection.HashSize; } #pragma warning restore 618 // calling obsolete methods } ////////////////////////////////////////////////////////////////////// // Step 4: Change binary ticket to managed struct // ** MSRC 11838 ** // Framework20 / Framework40 ticket generation modes are insecure. We should use a // secure serialization mode by default. if (!AppSettings.UseLegacyFormsAuthenticationTicketCompatibility) { return(FormsAuthenticationTicketSerializer.Deserialize(bBlob, ticketLength)); } // ** MSRC 11838 ** // If we have reached this point of execution, the developer has explicitly elected // to continue using the insecure code path instead of the secure one. We removed // the Framework40 serialization mode, so everybody using the legacy code path is // forced to Framework20. int iSize = ((ticketLength > MAX_TICKET_LENGTH) ? MAX_TICKET_LENGTH : ticketLength); StringBuilder name = new StringBuilder(iSize); StringBuilder data = new StringBuilder(iSize); StringBuilder path = new StringBuilder(iSize); byte [] pBin = new byte[4]; long [] pDates = new long[2]; int iRet = UnsafeNativeMethods.CookieAuthParseTicket(bBlob, ticketLength, name, iSize, data, iSize, path, iSize, pBin, pDates); if (iRet != 0) { return(null); } DateTime dt1 = DateTime.FromFileTime(pDates[0]); DateTime dt2 = DateTime.FromFileTime(pDates[1]); FormsAuthenticationTicket ticket = new FormsAuthenticationTicket((int)pBin[0], name.ToString(), dt1, dt2, (bool)(pBin[1] != 0), data.ToString(), path.ToString()); return(ticket); }
public static FormsAuthenticationTicket Decrypt(string encryptedTicket) { if (string.IsNullOrEmpty(encryptedTicket) || (encryptedTicket.Length > 0x1000)) { throw new ArgumentException(System.Web.SR.GetString("InvalidArgumentValue", new object[] { "encryptedTicket" })); } Initialize(); byte[] buf = null; if ((encryptedTicket.Length % 2) == 0) { try { buf = MachineKeySection.HexStringToByteArray(encryptedTicket); } catch { } } if (buf == null) { buf = HttpServerUtility.UrlTokenDecode(encryptedTicket); } if ((buf == null) || (buf.Length < 1)) { throw new ArgumentException(System.Web.SR.GetString("InvalidArgumentValue", new object[] { "encryptedTicket" })); } if ((_Protection == FormsProtectionEnum.All) || (_Protection == FormsProtectionEnum.Encryption)) { buf = MachineKeySection.EncryptOrDecryptData(false, buf, null, 0, buf.Length, false, false, IVType.Random); if (buf == null) { return(null); } } int length = buf.Length; if ((_Protection == FormsProtectionEnum.All) || (_Protection == FormsProtectionEnum.Validation)) { if (!MachineKeySection.VerifyHashedData(buf)) { return(null); } length -= MachineKeySection.HashSize; } if (!AppSettings.UseLegacyFormsAuthenticationTicketCompatibility) { return(FormsAuthenticationTicketSerializer.Deserialize(buf, length)); } int capacity = (length > 0x1000) ? 0x1000 : length; StringBuilder szName = new StringBuilder(capacity); StringBuilder szData = new StringBuilder(capacity); StringBuilder szPath = new StringBuilder(capacity); byte[] pBytes = new byte[4]; long[] pDates = new long[2]; if (System.Web.UnsafeNativeMethods.CookieAuthParseTicket(buf, length, szName, capacity, szData, capacity, szPath, capacity, pBytes, pDates) != 0) { return(null); } DateTime issueDate = DateTime.FromFileTime(pDates[0]); return(new FormsAuthenticationTicket(pBytes[0], szName.ToString(), issueDate, DateTime.FromFileTime(pDates[1]), pBytes[1] != 0, szData.ToString(), szPath.ToString())); }